數據結構與算法(五)-線性表之雙向鏈表與雙向循環鏈表


前言:前面介紹了循環鏈表,雖然循環鏈表可以解決單鏈表每次遍歷只能從頭結點開始,但是對於查詢某一節點的上一節點,還是頗為復雜繁瑣,所以可以在結點中加入前一個節點的引用,即雙向鏈表

一、簡介

   雙向鏈表:在鏈表中,每一個節點都有對上一個節點和下一個節點的引用或指針,即從一個節點出發可以有兩條路可選擇。
  雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數據結點中都有兩個指針或引用,分別指向直接后繼和直接前驅。所以,從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和后繼結點。一般我們都構造雙向循環鏈表。
   特性:
  • 遍歷可逆性:可以反向遍歷;
  • 相比於單鏈表,循環單鏈表無論是插入還是遍歷,更便利,更快捷;
  • 雙向鏈表可以有效的提高算法的時間性能,說白了就是用空間換時間;

二、雙向鏈表實現

   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;
        }

    }
    
}
BothwayLoopChain.java
   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版》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM