資料結構Java實現 ----迴圈連結串列、模擬連結串列
- 單向迴圈連結串列
- 雙向迴圈連結串列
- 模擬連結串列
一、單向迴圈連結串列:
1、概念:
單向迴圈連結串列是單鏈表的另一種形式,其結構特點是連結串列中最後一個結點的指標不再是結束標記,而是指向整個連結串列的第一個結點,從而使單鏈表形成一個環。
和單鏈表相比,迴圈單鏈表的長處是從鏈尾到鏈頭比較方便。當要處理的資料元素序列具有環型結構特點時,適合於採用迴圈單鏈表。
和單鏈表相同,迴圈單鏈表也有帶頭結點結構和不帶頭結點結構兩種,帶頭結點的迴圈單鏈表實現插入和刪除操作時,演算法實現較為方便。
帶頭結點的迴圈單鏈表的操作實現方法和帶頭結點的單鏈表的操作實現方法類同,差別僅在於:
(1)在建構函式中,要加一條head.next = head 語句,把初始時的帶頭結點的迴圈單鏈表設計成上圖中(a)所示的狀態。
(2)在index(i)成員函式中,把迴圈結束判斷條件current != null改為current != head。
2、單鏈表的程式碼實現:
先回顧上一篇文章,定位到第三段“三、單項鍊表的程式碼實現”,我們是需要修改這段裡面的(3)LinkList.java程式碼,(1)和(2)的程式碼不變。
(3)LinkList.java:單項迴圈連結串列類:(核心程式碼)
1 //單向迴圈連結串列類 2 public classCycleLinkList implements List { 3 4 Node head; //頭指標 5 Node current;//當前結點物件 6 int size;//結點個數 7 8 //初始化一個空連結串列 9 public CycleLinkList() 10 { 11 //初始化頭結點,讓頭指標指向頭結點。並且讓當前結點物件等於頭結點。 12 this.head = current = new Node(null); 13 this.size =0;//單向連結串列,初始長度為零。14 this.head.next = this.head; 15 } 16 17 //定位函式,實現當前操作物件的前一個結點,也就是讓當前結點物件定位到要操作結點的前一個結點。 18 //比如我們要在a2這個節點之前進行插入操作,那就先要把當前節點物件定位到a1這個節點,然後修改a1節點的指標域 19 public void index(int index) throws Exception 20 { 21 if(index <-1 || index > size -1) 22 { 23 throw new Exception("引數錯誤!"); 24 } 25 //說明在頭結點之後操作。 26 if(index==-1) //因為第一個資料元素結點的下標是0,那麼頭結點的下標自然就是-1了。 27 return; 28 current = head.next; 29 int j=0;//迴圈變數 30 while(current != head&&j<index) 31 { 32 current = current.next; 33 j++; 34 } 35 36 } 37 38 @Override 39 public void delete(int index) throws Exception { 40 // TODO Auto-generated method stub 41 //判斷連結串列是否為空 42 if(isEmpty()) 43 { 44 throw new Exception("連結串列為空,無法刪除!"); 45 } 46 if(index <0 ||index >size) 47 { 48 throw new Exception("引數錯誤!"); 49 } 50 index(index-1);//定位到要操作結點的前一個結點物件。 51 current.setNext(current.next.next); 52 size--; 53 } 54 55 @Override 56 public Object get(int index) throws Exception { 57 // TODO Auto-generated method stub 58 if(index <-1 || index >size-1) 59 { 60 throw new Exception("引數非法!"); 61 } 62 index(index); 63 64 return current.getElement(); 65 } 66 67 @Override 68 public void insert(int index, Object obj) throws Exception { 69 // TODO Auto-generated method stub 70 if(index <0 ||index >size) 71 { 72 throw new Exception("引數錯誤!"); 73 } 74 index(index-1);//定位到要操作結點的前一個結點物件。 75 current.setNext(new Node(obj,current.next)); 76 size++; 77 } 78 79 @Override 80 public boolean isEmpty() { 81 // TODO Auto-generated method stub 82 return size==0; 83 } 84 @Override 85 public int size() { 86 // TODO Auto-generated method stub 87 return this.size; 88 } 89 90 91 }
14行是新增的程式碼,30行是修改的程式碼。
3、單項迴圈連結串列的應用舉例:
編寫擊鼓傳花小遊戲。
遊戲規則:N個人圍成一個圈,從第一個人開始傳花,當數到M時,該人退出遊戲,直到剩下最後一個人。
程式碼實現:
(4)Game.java:
1 //遊戲類 2 public class Game { 3 4 //單向迴圈連結串列 5 CycleLinkList list = new CycleLinkList(); 6 //總人數 7 int num; 8 //數到幾退出 9 int key; 10 11 //遊戲初始化方法 12 public Game(int num,int key) 13 { 14 this.num = num; 15 this.key = key; 16 } 17 18 public void play() throws Exception 19 { 20 for(int i=0;i<num;i++) 21 { 22 list.insert(i, i); 23 } 24 25 System.out.println("\n-------遊戲開始之前---------\n"); 26 for(int i=0;i<list.size;i++) 27 { 28 System.out.print(list.get(i)+" "); 29 } 30 System.out.println("\n-------遊戲開始---------\n"); 31 int iCount=num; //開始等於總人數num 32 int j=0; //累加器,計算是否能被key整除。 33 34 Node node = list.head; 35 while(iCount!=1) 36 { 37 if(node.getElement()!=null&& Integer.parseInt(node.getElement().toString())!=-1) 38 { 39 j++; 40 if(j%key==0) 41 { 42 node.setElement(-1); 43 iCount--; 44 System.out.println(); 45 for(int i=0;i<list.size;i++) 46 { 47 System.out.print(list.get(i)+" "); 48 } 49 } 50 } 51 node = node.next; 52 } 53 System.out.println("\n-------遊戲結束---------\n"); 54 for(int i=0;i<list.size;i++) 55 { 56 System.out.print(list.get(i)+" "); 57 } 58 } 59 60 }
(5)Test.java:
1 public class Test { 2 3 /** 4 * @param args 5 */ 6 public static void main(String[] args) throws Exception { 7 // TODO Auto-generated method stub 8 /* 9 CycleLinkList list = new CycleLinkList(); 10 for(int i=0;i<10;i++) 11 { 12 int temp = ((int)(Math.random()*100))%100; 13 list.insert(i, temp); 14 System.out.print(temp+" "); 15 } 16 list.delete(4); 17 System.out.println("\n------刪除第五個元素之後-------"); 18 for(int i=0;i<list.size;i++) 19 { 20 System.out.print(list.get(i)+" "); 21 }*/ 22 23 Game game = new Game(10,3); 24 game.play(); 25 26 } 27 }
二、雙向迴圈連結串列:
雙向連結串列:
雙向連結串列是每個結點除後繼指標外還有一個前驅指標。和單鏈表類同,雙向連結串列也有帶頭結點結構和不帶頭結點結構兩種,帶頭結點的雙向連結串列更為常用;另外,雙向連結串列也可以有迴圈和非迴圈兩種結構,迴圈結構的雙向連結串列更為常用。
雙向迴圈連結串列:
在雙向連結串列中,每個結點包括三個域,分別是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表示要插入的結點,①、②、③、④表示實現插入過程的步驟:
迴圈雙向連結串列的刪除過程:
下圖中的指標p表示要插入結點的位置,①、②表示實現刪除過程的步驟:
2、雙向迴圈連結串列的程式碼實現:
(1)List.java:
1 //線性表介面 2 public interface List { 3 //獲得線性表長度 4 public int size(); 5 6 //判斷線性表是否為空 7 public boolean isEmpty();