一、 什么是链表?
链表是一种比较简单、很常见的数据结构,是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
二、链表的特点
链表是一种比较简单、很常见的数据结构,是线性表(List)的一种,是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。
1、插入删除效率高:任意位置插入元素和删除元素效率较高,时间复杂度为O(1)
2、灵活度高:链表不需要预先分配固定大小的空间,可以随着元素的增加自动扩容,因此不会出现内存不足的情况。
3、空间分散:在内存中,元素的空间可以在任意地方,空间是分散的,不需要连续。
4、查找效率低:查找数据时效率低,时间复杂度为O(N),因为链表的空间是分散的,所以不具有随机访问性,如要需要访问某个位置的数据,需要从第一个数据开始找起,依次往后遍历,直到找到待查询的位置,故可能在查找某个元素时,时间复杂度达到O(N)。
5、空间利用率高:空间不需要提前指定大小,是动态申请的,根据需求动态的申请和删除内存空间,扩展方便,故空间的利用率较高。
三、 如何构造链表
首先要先理解是怎么构建出链表,我们知道JVM里友栈区和堆区,栈区主要存引用,也就是一个指向实际对象的地址,而堆区存的才是创建的对象。
JVM构建链表图示:
实现单链表的完整代码:
public class BasicLink {
public static void main(String[] args) {
int[] a = {1, 2, 3};
Node node = getLinked(a);
System.out.println(node);
}
private static Node getLinked(int[] a) {
Node head = null;
Node newNode2 = new Node(a[2]);
Node newNode1 = new Node(a[1]);
Node newNode0 = new Node(a[0]);
head = newNode0;
newNode0.next = newNode1;
newNode1.next = newNode2;
return head;
}
}
class Node {
public int val;//节点值
public Node next;//指向下一个节点的引用
public Node(int var) {
this.val = var;
}
}
我们debug一下看一下从head开始next会发现是这样的:
这就是一个简单的线性访问了,所以链表就是从head开始,逐个开始向后访问,而每次所访问对象的类型都是一样的。
四、遍历链表
对于单链表,不管进行什么操作,一定是从头开始逐个向后访问,所以操作之后是否还能找到表头非常重要。
代码如下:
public void printLinkedList(Node head){
while(head != null){
System.out.print(head.val + "-");
head = head.next;
}
System.out.println("null");
}
五、链表的插入
单链表的插入,和数组的插入一样,过程不复杂,但是在编码时会发现处处时坑。单链表的插入操作需要考虑三种情况:首部、中部、尾部。
(1)表头插入
链表表头插入新结点非常简单,其实也就是在一辆火车的头部接入一个新的火车头。容易出错的是经常会忘了head需要重新指向表头。
代码如下:
Node newNode = new Node();
newNode.val = "新火车头";
newNode.next = head;
head = newNode
(2)中间插入
在中间位置插入,我们必须先遍历找到要插入的位置,然后将当前位置接入到前驱结点和后继结点之间,但是到了该位置之后我们却不能获得前驱结点了,也就无法将结点接入进来了。这就好比一边过河一边拆桥,结果自己也回不去了。
为此,我们要在目标结点的前一个位置停下来,也就是使用cur.next的值而不是cur的值来判断,这是链表最常用的策略。
例如下图中,如果要在7的前面插入,当cur.next = node(7)了就应该停下来,此时cur.val = 15。然后需要给newNode前后接两根线,此时只能先让new.next = node(15).nxet, 然后node(15).next = new,而且顺序还不能错。
想一想为什么不能颠倒顺序?
由于每个节点都只有一个next,因此执行了node(15).next=new之后,节点15和7之间的连线就自动断开了,如下图所示:
六、结尾插入
表尾插入就比较容易了,我们只要将尾结点指向新结点就行了。
七、链表删除
删除同样分为删除头部元素,删除中间元素和删除尾部元素。
(1)删除表头结点
只需要将头节点指向下一个节点即可。
if(head == null){ //判断链表是否为空列表
return;
}
head = head.nxet;
(2)删除最后一个结点
我们只要找到尾节点的上一个节点,然后将其指向null就可以。例如下图中删除40,其前驱节点是7.遍历的时候需要判断cur.next是否为40,如果是,则只要执行cur.next = null即可,此时节点40变得不可达,最终会被JVM回收掉。文章来源:https://www.toymoban.com/news/detail-627267.html
(3)删除中间结点
删除中间节点时,也会要用cur.next来比较,找到位置后,将cur.next指针的值更新为cur.next.next就可以解决,如下图所示:文章来源地址https://www.toymoban.com/news/detail-627267.html
到了这里,关于算法通关村第一关 | 链表青铜挑战笔记的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!