雙向循環鏈表的Java版本實現


  • 1、單項循環列表

     單向循環鏈表是單鏈表的另一種形式,其結構特點是鏈表中最后一個結點的指針不再是結束標記,而是指向整個鏈表的第一個結點,從而使單鏈表形成一個環。和單鏈表相比,循環單鏈表的長處是從鏈尾到鏈頭比較方便。當要處理的數據元素序列具有環型結構特點時,適合於采用循環單鏈表。

  • 2、單向循環鏈表

     和單鏈表相同,循環單鏈表也有帶頭結點結構和不帶頭結點結構兩種,帶頭結點的循環單鏈表實現插入和刪除操作時,算法實現較為方便。帶頭結點的循環單鏈表結構如下:

     

 

帶頭結點的循環單鏈表的操作實現方法和帶頭結點的單鏈表的操作實現方法類同,差別僅在於:

(1)在構造函數中,要加一條head.next = head 語句,把初始時的帶頭結點的循環單鏈表設計成圖2-11 (a)所示的狀態。

(2)在index(i)成員函數中,把循環結束判斷條件current != null改為current != head。

  • 雙向循環鏈表

      雙向鏈表是每個結點除后繼指針外還有一個前驅指針。和單鏈表類同,雙向鏈表也有帶頭結點結構和不帶頭結點結構兩種,帶頭結點的雙向鏈表更為常用;另外,雙向鏈表也可以有循環和非循環兩種結構,循環結構的雙向鏈表更為常用

      在雙向鏈表中,每個結點包括三個域,分別是element域、next域和prior域,其中element域為數據元素域,next域為指向后繼結點的對象引用,prior域為指向前驅結點的對象引用。

如下圖是帶頭結點的循環雙向鏈表的圖示結構。循環雙向鏈表的next和prior各自構成自己的循環單鏈表。

在雙向鏈表中,有如下關系:設對象引用p表示雙向鏈表中的第i個結點,則p.next表示第i+1個結點,p.next.prior仍表示第i個結點,即p.next.prior == p;同樣地,p.prior表示第i-1個結點,p.prior.next仍表示第i個結點,即p.prior.next == p。下圖是雙向鏈表上述關系的圖示。

循環雙向鏈表的插入過程如下圖所示。圖中的指針p表示要插入結點的位置,s表示要插入的結點,①、②、③、④表示實現插入過程的步驟。

 

 

 //==========================================我是代碼的分割線

//具體代碼的分析已經詳細的寫在了解析里面,歡迎討論

 1 /**
 2  * 本項目主要是通過幾個類來組合實現
 3  * 1、List的線性表的接口
 4  * 2、Node節點類的具體方法
 5  * 3、單項鏈表類的具體實現
 6  */
 7 
 8 
 9 /**
10  * 線性表接口
11  */
12 public interface List {
13 
14     // 獲得線性表的長度
15     public int size();
16 
17     // 判斷是否為空
18     public boolean isEmpty();
19 
20     // 插入操作,需要拋出異常
21     public void insert(int index, Object obj) throws Exception;
22 
23     // 刪除元素
24     public void delete(int index) throws Exception;
25 
26     // 獲取指定位置元素
27     public Object get(int index) throws Exception;
28 
29 }
List interface
//節點類
//這個是重點!!!!Java一樣可以實現指針的跳轉->使用引用
public class Node {

    Object element; // 數據域
    Node next;// 后繼指針域
    Node prior;// 前驅指針域

    // 頭節點的構造方法
    public Node(Node nextval) {
        this.next = nextval;
    }

    // 非頭節點的構造方法
    public Node(Object obj, Node nextval) {
        this.element = obj;
        this.next = nextval;
    }

    // 獲得當前節點的后繼結點
    public Node getNext() {
        return this.next;
    }

    // 獲得當前節點的前驅結點
    public Node getPrior() {
        return this.prior;
    }

    // 獲得當前節點的數據域的值
    public Object getElement() {
        return this.element;
    }

    // 設置當前節點的后繼指針域
    public void setNext(Node nextval) {
        this.next = nextval;
    }

    // 設置當前節點的前驅指針域
    public void setPrior(Node priorval) {
        this.prior = priorval;
    }

    
    // 設置當前節點的數據域,
    public void setElement(Object obj) {
        this.element = obj;
    }

    public String toString() {
        return this.element.toString();
    }
}
View Code
 1 //單向鏈表類
 2 public class DoubleCycleLinkList implements List {
 3 
 4     Node head;// 頭指針
 5     Node current;// 當前節點對象
 6     int size; // 節點的個數
 7 
 8     // 初始化一個空鏈表
 9     public DoubleCycleLinkList() {
10         // 初始化頭節點,讓頭指針指向頭節點,並且讓當前節點對象等於頭節點
11         this.head = current = new Node(null);
12         this.size = 0; // 單項鏈表出事長度為0
13         // 循環列表屬性
14         this.head.next = head;
15         this.head.prior = head;
16     }
17 
18     // 定位函數,實現當前操作對象的前一個節點,也就是讓當前節點對象定位到要要操作節點的前一個節點
19     public void index(int index) throws Exception {
20         // 參數非法時,出現-1是由於第一個元素的下標是0,而第一個元素的前面就是頭節點,該節點就得用-1表示下標了。
21         if (index < -1 || index > size - 1) {
22             throw new Exception("參數錯誤");
23         }
24         // 說明是在頭節點之后進行操作
25         if (index == -1)
26             return;
27         // 通過該循環獲得要操作的那個數的前一個節點
28         current = head.next;
29         int j = 0;// 循環變量
30         // 循環鏈表屬性
31         while (current != head && j < index) {
32             current = current.next;
33             j++;
34         }
35 
36     }
37 
38     @Override
39     public int size() {
40         // TODO Auto-generated method stub
41         return this.size;
42     }
43 
44     @Override
45     public boolean isEmpty() {
46         // TODO Auto-generated method stub
47         return size == 0;
48     }
49 
50     @Override
51     public void insert(int index, Object obj) throws Exception {
52         // TODO Auto-generated method stub
53         // 可以等於0表示在一個元素的前面插入,也就是頭結點的后面
54         if (index < 0 || index > size) {
55             throw new Exception("參數錯誤! ");
56         }
57         /**
58          * 這里是核心操作
59          */
60         // 定位到要操作節點的前一個節點對象
61         index(index - 1);
62         // 將前一個節點進行設置,使其指向要插入節點的指針域,
63         current.setNext(new Node(obj, current.next));
64         size++;
65     }
66 
67     @Override
68     public void delete(int index) throws Exception {
69         // TODO Auto-generated method stub
70         if (isEmpty()) {
71             throw new Exception("鏈表為空,無法刪除");
72         }
73 
74         if (index < 0 || index > size) {
75             throw new Exception("參數錯誤!");
76         }
77         // 進行定位
78         index(index - 1);
79         // current此時表示要刪除節點的前一個節點的指示,因此需要將該節點指向要刪除的那個節點的下一個節點才對
80         // 修改后繼指針
81         current.setNext(current.next.next);
82         // 修改前驅指針
83         current.next.setPrior(current);
84         size--;
85 
86     }
87 
88     @Override
89     public Object get(int index) throws Exception {
90         // TODO Auto-generated method stub
91         if (index < -1 || index > size - 1) {
92             throw new Exception("參數非法,無法查詢");
93         }
94         // 先定位
95         index(index);
96         return current;
97     }
98 }

 

//測試類
public class Test {
    public static void main(String[] args) throws Exception {
        DoubleCycleLinkList list = new DoubleCycleLinkList();
        for (int i = 0; i < 10; i++) {
            // 0-99之間的整數
            int temp = (int) (Math.random() * 100);
            list.insert(i, temp);
            System.out.print(temp + " ");
        }

        list.delete(4);
        System.out.println();
        System.out.println("----刪除第五個元素之后------");
        for (int i = 0; i < list.size; i++) {
            System.out.print(list.get(i) + " ");
        }
    }
}
View Code

 


免責聲明!

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



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