java實現雙向鏈表

一 前言

以前知識知識追尋者寫了一篇單鏈表的實現,感受不是很滿意,寫的邏輯不夠清晰,有些地方實現的不過好,不能連成一個總體,僞單鏈表;爲此研究了一會雙向鏈表的簡單實現;本篇的實現方式是以方法的形式展示,讀者能夠將其整合爲一個類;測試

二 雙向鏈表簡介

雙向鏈表的定義是,一個節點有兩個方向,分別儲存當前節點的前驅節點,和後續節點;雙向鏈表的刪除只須要指定前驅節點,或者後續節點就能夠進行刪除操做;可是缺點也很明顯每次添加節點時都須要2個指向,額外增長了內存空間消耗;指針

三 雙向鏈表的實現

3.1 定義鏈表節點

  1. 定義data存儲數據,知識追尋者使用的時int類型,讀者能夠改成object類型;
  2. 定義前驅節點previous
  3. 定義後續節點next
/**
 * @Author lsc
 * <p> 雙向鏈表節點 </p>
 */
public class DoubleNode {

    //數據
    private Integer data;
    //後續節點節點
    private DoubleNode next;
    //前驅節點
    private DoubleNode previous;
    // 省略set get
}

3.2 插入頭節點

思路以下code

  1. 將新節點的前驅節點指向nul
  2. 新節點的後續節點指向表頭
  3. 將表頭的前驅節點指向新節點
public class DoubleList {

    private DoubleNode head;

    /* *
     * @Author lsc
     * <p> 表頭插入節點
     *  思路: 1 將新節點的前驅節點指向null,
     *        2新節點的後續節點指向表頭
     *        3 將表頭的前驅節點指向新節點
     * </p>
     * @Param [data]
     * @Return void
     */
   public void addFirst(int data){
       // 建立新節點
       DoubleNode newNode = new DoubleNode();
       // 爲新節點添加數據
       newNode.setData(data);
       // 若是表頭爲空直接將新節點做爲頭
       if (head==null){
           head = newNode;
       }else {
           // 將新節點的前驅節點指向null(聲明的時候原本就是null)
           //新節點的後續節點指向表頭
           newNode.setNext(head);
           // 將表頭的前驅節點指向新節點
           head.setPrevious(newNode);
           // head從新賦值
           head = newNode;
       }
   }
     /* *
     * @Author lsc
     * <p>順序打印鏈表
      思路:從鏈表的頭遍歷到鏈表的尾巴
     * </p>
     * @Param []
     * @Return void
     */
   public void displayNext(){
       // 將表頭做爲當前節點
       DoubleNode currentNode = head;
       // 遍歷鏈表
       while (currentNode!=null){
           // 打印數據
           System.out.println(currentNode.getData());
           // 將下一個節點做爲當前節點
           currentNode = currentNode.getNext();
       }
   }
}

測試代碼以下,往前插入數據,打印出來就是倒序blog

public static void main(String[] args) {
        DoubleList doubleList = new DoubleList();
        for (int i = 0; i <5 ; i++) {
            doubleList.addFirst(i);
        }
        doubleList.displayNext();
    }

結果索引

4
3
2
1
0

3.3 插入尾節點

思路以下內存

  1. 表尾的後續節點指向新節點
  2. 新節點的前驅節點指向表尾
  3. 新節點的後續節點指向null
/* *
     * @Author lsc
     * <p> 表尾插入節點
     * 思路 : 1 表尾的後續節點指向新節點
     *        2 新節點的前驅節點指向表尾
     *        3 新節點的後續節點指向null
     * </p>
     * @Param [data]
     * @Return void
     */
   public void addLast(int data){
       // 建立新節點
       DoubleNode newNode = new DoubleNode();
       // 爲新節點添加數據
       newNode.setData(data);
       // 若是表頭爲空直接將新節點做爲頭
       if (head==null){
           head = newNode;
       }else {
           DoubleNode currentNode = head;
           //尋找尾節點
           while (currentNode.getNext()!=null){
               currentNode = currentNode.getNext();
           }
           //表尾的後續節點指向新節點
           currentNode.setNext(newNode);
           //新節點的前驅節點指向表尾
           newNode.setPrevious(currentNode);
       }
   }

測試代碼以下,往表爲插入數據,也就是順序打印rem

public static void main(String[] args) {
        DoubleList doubleList = new DoubleList();
        for (int i = 0; i <5 ; i++) {
            //doubleList.addFirst(i);
            doubleList.addLast(i);
        }
        doubleList.displayNext();
    }

結果get

0
1
2
3
4

3.4 獲取鏈表長度

思路 :遍歷鏈表,一個節點表明一個單位的長度io

/* *
     * @Author lsc
     * <p> 得到鏈表長度
     * 思路:遍歷鏈表,一個節點表明一個單位的長度
     *  </p>
     * @Param []
     * @Return int
     */
   public int length(){
       int length = 0;
       // 當前節點
       DoubleNode currentNode = head;
       while (currentNode!=null){
           // 一個節點 length 長度就加1
            length++;
            // 將下一個節點做爲當前節點
            currentNode = currentNode.getNext();
       }
       return length;
   }

3.5 指定位置插入節點

思路: 假設在BC直接插入新節點Nast

  1. ​ B 節點的後續節點指向 N
  2. N 節點 的前驅節點指向 B
  3. N 節點的後續節點指向 C
  4. C 節點的前驅節點指向 N

重要的也就是要找到B節點的位置,轉存C節點;

/* *
    * @Author lsc
    * <p> 指定位置插入節點
    * 思路: 假設在AB直接插入新節點N
    *       1 A 節點的後續節點指向 N
    *       2 N 節點 的前驅節點指向 A
    *       3 N 節點的後續節點指向 B
    *       4 B 節點的前驅節點指向 N
    * 重點也是找到A節點的位置
    *  </p>
    * @Param [data]
    * @Return void
    */
   public void add(int data, int index){
       // 索引超出,非法
       if (index<0 || index>length()){
           System.out.println("非法索引");
           return;
       }
       // 若是索引爲0,調用addFirst方法
       if (index==0){
           addFirst(data);
           return;
       }
       // 若是索引等於鏈表的長度,調用addLast方法
       if (index==length()){
           addLast(data);
           return;
       }
       // 建立新節點
       DoubleNode newNode = new DoubleNode();
       // 爲新節點添加數據
       newNode.setData(data);
       // 當前節點
       DoubleNode currentNode = head;
       // 定義指針
       int point = 0;
       // 尋找插入新節點的上一個節點A
       while ((index-1)!= point){
           currentNode = currentNode.getNext();
           point++;
       }
       // 轉存當前節點的後續節點
       DoubleNode nextNode = currentNode.getNext();
       // 當前節點的後續節點指向新節點
       currentNode.setNext(newNode);
       // 新接的前驅節點指向當前節點
       newNode.setPrevious(currentNode);
       // 新節點的後續節點指向轉存的節點
       newNode.setNext(nextNode);
       // 轉存節點的前驅節點指向新節點
       nextNode.setPrevious(newNode);

   }

測試代碼

public static void main(String[] args) {
        DoubleList doubleList = new DoubleList();
        for (int i = 0; i <5 ; i++) {
            doubleList.addLast(i);
        }
        doubleList.add(666,3);
        doubleList.displayNext();
    }

結果

0
1
2
666
3
4

3.6 刪除表頭

思路以下

  1. 建立一個臨時節點,存儲表頭的後續節點
  2. 將臨時節點的前驅節點指向null
  3. 將臨時節點賦值給表頭
/* *
    * @Author lsc
    * <p> 刪除表頭
     思路: 1 建立一個臨時節點,存儲表頭的後續節點
     *     2 將臨時節點的前驅節點指向null
     *     3 將臨時節點賦值給表頭
    * </p>
    * @Param []
    * @Return void
    */
   public void removeFirst(){
       if (length()==0){
           return;
       }
       // 只有一個節點直接清空表頭
       if (length()==1){
           head=null;
           return;
       }
       // 建立一個臨時節點,存儲表頭的後續節點
       DoubleNode temNode = head.getNext();
       // 將臨時節點的前驅節點指向null
       temNode.setPrevious(null);
       // 將臨時節點賦值給表頭
       head = temNode;
   }

測試代碼

public static void main(String[] args) {
        DoubleList doubleList = new DoubleList();
        for (int i = 0; i <5 ; i++) {
            doubleList.addLast(i);
        }
        doubleList.removeFirst();
        doubleList.displayNext();
    }

結果

1
2
3
4

3.7 刪除表尾

思路

  1. 找到表尾的前驅節點
  2. 將表尾的前驅節點的後續節點置爲null
/* *
    * @Author lsc
    * <p> 刪除表尾
        思路: 1 找到表尾的前驅節點
        *     2 將表尾的前驅節點的後續節點置爲null
        *     3
    * </p>
    * @Param []
    * @Return void
    */
   public void removeLast(){
        if (length()==0){
            return;
        }
       // 只有一個節點直接清空表頭
       if (length()==1){
           head=null;
           return;
       }
       DoubleNode previousNode = head;
       // 尋找尾節點的前驅節點
       while (previousNode.getNext().getNext()!=null){
           previousNode = previousNode.getNext();
       }
       previousNode.setNext(null);
   }

測試代碼

public static void main(String[] args) {
        DoubleList doubleList = new DoubleList();
        for (int i = 0; i <5 ; i++) {
            //doubleList.addFirst(i);
            doubleList.addLast(i);
        }
        doubleList.removeLast();
        doubleList.displayNext();
    }

結果

0
1
2
3

3.8 刪除指定節點

思路: 假設有BCD節點要刪除B節點

  1. 將 B 節點的後續節點指向 D節點
  2. 將D節點前驅節點指向B節點

重要的也就是要找到B節點位置,轉存D節點;

/* *
    * @Author lsc
    * <p>  指定位置刪除節點
      思路: 假設有ABC節點要刪除B節點
      *     1 將 A 節點的後續節點指向 C節點
      *     2 將C節點前驅節點指向A節點
    * </p>
    * @Param [index]
    * @Return void
    */
   public void remove(int index){
       if (index<0 || index>=length()){
           System.out.println("非法索引");
           return;
       }
       // 頭節點
       if (index==0){
           removeFirst();
           return;
       }
       // 尾節點
       if (index==(length()-1)){
           removeLast();
           return;
       }
       // 欲想刪除節點的前驅節點
       DoubleNode previousNode = head;
       // 定義指針
       int point = 0;
       // 尋找新節
       while ((index-1)!=point){
           previousNode = previousNode.getNext();
           point++;
       }
       // 欲想刪除節點的後續節點
       DoubleNode nextNode = previousNode.getNext().getNext();
       // 將欲想刪除節點的前驅節點的後續節點指向欲想刪除節點的後續節點
       previousNode.setNext(nextNode);
       // 將欲想刪除節點的後續節點的前驅節點指向欲想刪除節點的前驅節點
       nextNode.setPrevious(previousNode);

   }

測試代碼

public static void main(String[] args) {
        DoubleList doubleList = new DoubleList();
        for (int i = 0; i <5 ; i++) {
            //doubleList.addFirst(i);
            doubleList.addLast(i);
        }
        doubleList.remove(3);
        doubleList.displayNext();
    }

結果

0
1
2
4
相關文章
相關標籤/搜索