前言:前面介紹了循環鏈表,雖然循環鏈表可以解決單鏈表每次遍歷只能從頭結點開始,但是對於查詢某一節點的上一節點,還是頗為復雜繁瑣,所以可以在結點中加入前一個節點的引用,即雙向鏈表
一、簡介
雙向鏈表:在鏈表中,每一個節點都有對上一個節點和下一個節點的引用或指針,即從一個節點出發可以有兩條路可選擇。
雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數據結點中都有兩個指針或引用,分別指向直接后繼和直接前驅。所以,從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和后繼結點。一般我們都構造雙向循環鏈表。


特性:
- 遍歷可逆性:可以反向遍歷;
- 相比於單鏈表,循環單鏈表無論是插入還是遍歷,更便利,更快捷;
- 雙向鏈表可以有效的提高算法的時間性能,說白了就是用空間換時間;
二、雙向鏈表實現
1、創建節點類Node,其中有三個屬性pre、object、next,pre為上一個節點的引用,也叫作前驅節點,object存儲數據,next為下一個節點的引用,也叫作后繼節點:

public class BothwayLoopChain<T> { //頭結點直接引用 private Node<T> head; //鏈長度 private Integer size; //初始化 BothwayLoopChain() { head = new Node<T>(); head.setNext(null); size = 0; } class Node<T> { private Node<T> pre; private Object object; private Node<T> next; public Node<T> getPre() { return pre; } public void setPre(Node<T> pre) { this.pre = pre; } public Object getObject() { return object; } public void setObject(Object object) { this.object = object; } public Node<T> getNext() { return next; } public void setNext(Node<T> next) { this.next = next; } } }
2、獲取位置的結點:
public T get(Integer index) throws Exception { return (T) getNode(index).getObject(); } private Node<T> getNode(Integer index) throws Exception { if (index > size || index < 0) { throw new Exception("index outof length"); } Node<T> p = head; for (int i = 0; i < index; i++) { p = p.next; } return p; }
3、插入節點:
//在尾節點后插入節點 public void add(T t) throws Exception { this.add(t,size); } //在index位置后插入一個節點 public void add(T t, Integer index) throws Exception { //創建新節點 Node<T> p = new Node<>(); p.setObject(t); //獲取該位置的節點 Node<T> s = getNode(index); p.setPre(s); if (s.getNext() != null) { //將本節點的next節點放入新節點的next節點 p.setNext(s.getNext()); s.getNext().setPre(p); } else { p.setNext(null); } size++; }
4、移除節點:
//移除節點並返回 public Node<T> remove(Integer index) throws Exception { //獲取該位置的節點 Node<T> s = getNode(index); //獲取該位置節點的下一個節點 Node<T> next = s.getNext(); //將本節點的pre節點的next節點設置為next s.getPre().setNext(next); next.setPre(s.getPre()); return s; }
至此,雙向鏈表的基本實現已完成,其實它就是
用空間換時間來提高性能的;
之前了解了單鏈表的循環結構即單向循環鏈表,舉一反三,雙向鏈表也有循環結構,即雙向循環鏈表;
三、雙向鏈表擴展—雙向循環鏈表
在雙向鏈表的基礎上進行改造:
- 尾節點的next指向頭結點;
- 頭結點的pre指向尾節點;


除了插入方法,其他方法可保持不變:
//在index位置后插入一個節點 public void add(T t, Integer index) throws Exception { //創建新節點 Node<T> p = new Node<>(); p.setObject(t); //獲取該位置的節點 Node<T> s = getNode(index); p.setPre(s); //將本節點的next節點放入新節點的next節點 p.setNext(s.getNext()); s.getNext().setPre(p); size++; }
本系列參考書籍:
《寫給大家看的算法書》
《圖靈程序設計叢書 算法 第4版》