什么是链表?链表是一种物理存储结构上非连续存储结构,数据元素的逻辑顺序是通过链表中的引用链接次序实现的 。 就如现实中的火车或铁链一般,环环相扣。当我们到达一个节点时,就可以通过这个节点找到下一个节点。链表与顺序表一样,都是线性结构,如果你没学过数据结构,那么可能会问,既然有了顺序表,为什么还要链表呢?那是因为它们的作用范围不同,如顺序表它的底层便是一个数组,既然是数组,那么它便不可避免的具有数组的小毛病,那就是不好删除和插入。我猜可能会有人说:“哎哎哎,谁说数组不好删除和插入了,我几个代码就将它给做到了。”,对你来说是几行代码的事情,但是对计算机来说,就得重复n遍了,倘若数组的成员有许多,那么不久拖累了效率了吗?那么有没有一下就能做好这件事的呢?当然有,那就是链表,毕竟你往铁链里面插入一个节点,只需在其位置断开后面的,然后将新的节点接在后面,同时把断下来的部分接在新节点后面就行,而不是如数组一样,将后面一个一个往前面覆盖。
就连火车都分动铁和高铁等样式,链表自然也多种多样,共有着8种链表。为什么是8种,因为链表有着如下特点,将它们组合起来就只有8种。
public class ListNode {
int val;
ListNode next;
ListNode() {}
ListNode(int val) { this.val = val; }
ListNode(int val, ListNode next) { this.val = val; this.next = next; }
}
//头插法 public void addFirst(int data); //尾插法 public void addLast(int data); //任意位置插入,第一个数据节点为0号下标 public boolean addIndex(int index,int data); //查找是否包含关键字key是否在单链表当中 public boolean contains(int key); //删除第一次出现关键字为key的节点 public void remove(int key); //删除所有值为key的节点 public void removeAllKey(int key); //得到单链表的长度 public int size(); public void display(); public void clear();
public void addFirst(int value){ if(this.head == null){ head = new Node(value); }else { Node node = new Node(value); node.setNext(head); head = node; } size++;//这是用来统计链表的长度的。 }
而尾插法也与它大同小异,唯一的问题就是如何找到原尾节点在哪。我们要想找到尾节点的话,就要知道它与其它节点的不同,它的后面没有链接任何东西,也就是它的next为空,因此,我们只需遍历整个链表尾节点了,那么怎么遍历呢?我们可以先定义一个变量记录头节点的位置,因为我们要遍历的话,就必然要顺着链条往下走,如果我们不记录头节点的位置,那么头节点的位置也会随着往下走,那岂不是前面的节点都找不到了。因此我们得定义一个变量,当我们定义好后,就该开始遍历了,我们得判断当前变量的next是不是为空,倘若是,则停止遍历,倘如不是,则让该变量指向该变量的next,然后重复以上操作,直到找到尾节点为止。
public void addLast(int value){ if(this.head == null){ head = new Node(value); }else { Node cur = head; while (cur.Next != null){ cur = cur.Next; } cur.next = new Node(value); } size++; }
展示链表也是通过遍历来进行的,不过是将寻找尾节点的过程中的所有数据都展示出来罢了,而添加也较为简单,我们可以先确定要添加的位置,然后通过双指针遍历找到该位置与该位置的上一个节点,然后与头插法一样,将其添加进去,然后将用双指针找到的该位置的上一个节点的next指向要添加的数据节点,并让该数据节点的next指向原该位置(也通过双指针找到了)。删除也与之大差不差,就不一一写了。那么我们来写我认为是链表中最难的,就是删除所有值为key(我们要删的)的节点,也许有人会说,这也太简单了,只要将删除的操作循环不就行。没错·,这样也行,但这样我们得循环好多次,如果该链表全是我们要删除的,那得循环多少次才行,因此我们得在一次遍历中就将它全部删除。我们还是用双指针来解决,与删除一样,当我们通过快指针找到要删除的节点后,慢指针刚好指向该节点的前一个,然后我们将快指针指向要删除节点的后面,慢指针指向快指针,然后继续遍历,直到快指针为空就全部删除完。
public void removeAll(int value){ if(head == null){ return; } int count = 0;//记录删除节点的个数 Node prev = head; Node cur = prev.next; while(cur != null){ if(cur.data == value){ count++; cur = cur.next; if(cur == null){ prev.next = null; } continue; } prev.next = null; prev = cur; cur = cur.next; } if(head.data == value){//如果头节点也要删的话 head = head.next; count++; } size = size - count;//计算此时链表的长度 }
剩下的就没太大难度了,就不罗嗦了。