引言
上片文章我们介绍无头非循环单向链表的实现,这篇文章我们将继续介绍另外一种常见的无头双向链表的实现。
1.双向链表的结构
每个节点包含一个前驱节点和一个后继节点。
2.无头双向链表的模拟实现
javapublic class MyLinkedList { class ListNode { int val; ListNode prev; ListNode next; public ListNode(int val) { this.val = val; } } public ListNode head; public ListNode last; //头插法 public void addFirst(int data){ ListNode node = new ListNode(data); if(head == null) { head = last = node; } else { node.next = head; head.prev = node; head = node; } } //尾插法 public void addLast(int data){ ListNode node = new ListNode(data); if(head == null) { head = last = node; } else { last.next = node; node.prev = last; last = node; } } //任意位置插入,第一个数据节点为0号下标 public void addIndex(int index,int data){ int len = size(); if(index<0||index>len) { return; } if(index == 0) { addFirst(data); return; } if(index == len) { addLast(data); return; } ListNode node = new ListNode(data); ListNode cur = findIndex(index); node.next = cur; cur.prev.next = node; node.prev = cur.prev; cur.prev = node; } //根据下标查找节点 public ListNode findIndex(int index) { ListNode cur = head; while(index!=0) { cur = cur.next; index--; } return cur; } //查找是否包含关键字key是否在单链表当中 public boolean contains(int key){ ListNode cur = head; while(cur != null) { if(cur.val == key) { return true; } cur = cur.next; } return false; } //删除第一次出现关键字为key的节点 public void remove(int key){ ListNode cur = head; while (cur!=null) { if(cur.val == key) { //开始删除 if(cur == head) { head = head.next; if(head != null) { head.prev = null; } }else{ cur.prev.next = cur.next; if(cur.next == null){ last = last.prev; }else { cur.next.prev = cur.prev; } } return; } cur = cur.next; } } //删除所有值为key的节点 public void removeAllKey(int key){ ListNode cur = head; while (cur!=null) { if(cur.val == key) { //开始删除 if(cur == head) { head = head.next; if(head != null) { head.prev = null; } }else{ cur.prev.next = cur.next; if(cur.next == null){ last = last.prev; }else { cur.next.prev = cur.prev; } } } cur = cur.next; } } //得到单链表的长度 public int size(){ ListNode cur = head; int count = 0; while(cur != null) { count++; cur = cur.next; } return count; } public void display(){ ListNode cur = head; while(cur != null) { System.out.println(cur.val + " "); cur = cur.next; } System.out.println(); } public void clear(){ ListNode cur = head; while(cur != null) { ListNode curN = cur.next; cur.prev = null; cur.next = null; cur = curN; } head = last = null; } }
3.什么是LinkedList
LinkedList的底层是双向链表结构,由于链表没有将元素存储在连续的空间中,元素存储在单独的节点中,然后通过引用将节点连接起来了,因此在任意位置插入或者删除元素时,不需要搬移元素,效率比较高。
在集合框架中,LinkedList也实现了List接口,具体如下:
【说明】
- LinkedList实现了List接口
- LinkedList的底层使用了双向链表
- LinkedList没有实现RandomAccess接口,因此LinkedList不支持随机访问
- LinkedList的任意位置插入和删除元素时效率比较高,时间复杂度为O(1)
- LinkedList比较适合任意位置插入的场景