轉載請注明本文出處:http://www.cnblogs.com/Starshot/p/6918569.html
鏈表的結構是由一個一個節點組成的,所謂鏈,就是每個節點的頭尾連在一起。而單向鏈表就是:每個節點包含了當前節點的值和下一個節點引用。雙向鏈表就是每個節點包含了當前節點的值和上下兩個節點的引用。相對於數組結構,鏈表的增刪效率會更加高。
這邊文章主要講怎么用Java實現一個簡單的鏈表結構:單向無環鏈表。以及實現一些數據處理的方法。
首先,新建一個節點類(本次例子中的節點值都是字符串類型):
1 public class Node { 2 3 private String value; 4 private Node next; 5 6 public Node(String value){ 7 this.value=value; 8 } 9 public Node(){ 10 11 } 12 13 public String getValue(){ 14 return value; 15 } 16 17 public Node getnext(){ 18 return next; 19 } 20 21 public void setValue(String value){ 22 this.value=value; 23 } 24 25 public void setNext(Node next){ 26 this.next=next; 27 } 28 }
然后再建一個鏈表類:
public class MyLinkedTable { Node head=new Node(); //向鏈表中增加值 public boolean add(String str){ Node node=new Node(str); if(head.getnext()==null){ head.setNext(node);; return true; } Node tmp=head; while(tmp.getnext()!=null){ tmp=tmp.getnext(); } tmp.setNext(node); return true; } //已知某個節點,然后刪除該節點 public boolean delete(Node node){ Node next=node.getnext(); Node nextAddress=next.getnext(); String nextValue=next.getValue(); node.setNext(nextAddress); node.setValue(nextValue); return true; } //刪除第index個節點,index從1開始 public boolean delete(int index){ if(index>length()||index<1){ return false; } int i=1; Node temp=head.getnext(); while(i<index){ temp=temp.getnext(); i++; } Node next=temp.getnext(); Node nextAddress=next.getnext(); String nextValue=next.getValue(); temp.setNext(nextAddress); temp.setValue(nextValue); return true; } //獲得第index個節點的值 public String get(int index){ if(index>length()||index<1){ return null; } int i=1; Node temp=head.getnext(); while(i<index){ temp=temp.getnext(); i++; } return temp.getValue(); } //獲取鏈表里面數據的長度,也就是插入了多少個值。 public int length(){ if(head.getnext()==null){ return 0; } int i=1; Node temp=head.getnext(); while((temp=temp.getnext())!=null){ i++; } return i; } //反轉鏈表 public void reverseTable(){ Node node1=head.getnext(); if(node1==null){ return; } Node preNode=null; Node curNode=node1; while(true){ Node origNextNode=curNode.getnext(); curNode.setNext(preNode); if(origNextNode==null){ head.setNext(curNode); break; } preNode=curNode; curNode=origNextNode; } } //獲取中間鏈表 public String getMid(){ Node slowPointer=this.head.getnext(),fastPointer=this.head.getnext(); while(fastPointer!=null&&fastPointer.getnext()!=null&&fastPointer.getnext().getnext()!=null){ slowPointer=slowPointer.getnext(); fastPointer=fastPointer.getnext().getnext(); } return slowPointer.getValue(); } //刪除重復鏈表 public void deleteDuplicateNode(){ Node nodeCur=head.getnext(); if(nodeCur==null) return; while(nodeCur.getnext()!=null){ Node lastNode=nodeCur; Node compareNode=lastNode.getnext(); while(compareNode!=null){ if(nodeCur.getValue().equals(compareNode.getValue())){ lastNode.setNext(compareNode.getnext()); compareNode=compareNode.getnext(); }else{ lastNode=compareNode; compareNode=compareNode.getnext(); } } nodeCur=nodeCur.getnext(); } } }
需要說明一下,這個鏈表結構是以head為起始節點,head指向插入的第一個節點(反轉后就是最后一個),head本身的value一直都是空的,它只作為起始節點入口存在,不參與節點的計數,所以鏈表的節點總數(插入數據總數)是不包括head在內的。
接下來對某些方法進行說明:
1.鏈表反轉
//鏈表翻轉就是把原來的1>2>3>4變成4>3>2>1,所以原來在最前面的節點要變成在最后面,最后面的要變成最前面 //就是head的地址引用要變成最后一個節點的,原來head后的第一個節點的地址引用要由第二的節點變為NULL,原來第二個節點的地址引用要由第三個節點變成第一個節點 //以此類推,一直翻轉到最后一個。然后把head的地址引用變成最后一個。 //在這個鏈表里面,head的位置是一直不變的,它永遠是最前面,在head之后的節點才開始翻轉。 public void reverseTable(){ Node node1=head.getnext(); if(node1==null){ return; } Node preNode=null; Node curNode=node1; while(true){ Node origNextNode=curNode.getnext(); curNode.setNext(preNode); if(origNextNode==null){ head.setNext(curNode); break; } preNode=curNode; curNode=origNextNode; } }
2.獲得中間節點:
//通過用快慢指針來找到中間節點,快指針的速度為慢指針的兩倍,慢指針一次走一個節點,快指針一次走兩個節點, //當快指針走到盡頭時,慢指針剛好為中間值,當快指針走到倒數第二個節點時,慢指針為上中位數。 //fastPointer!=null用來判斷鏈表表內除head外有沒有其它節點,fastPointer.getnext()!=null判斷是否為最后一個節點, //fastPointer.getnext().getnext()!=null判斷是否為倒數第二個節點。 public String getMid(){ Node slowPointer=this.head.getnext(),fastPointer=this.head.getnext(); while(fastPointer!=null&&fastPointer.getnext()!=null&&fastPointer.getnext().getnext()!=null){ slowPointer=slowPointer.getnext(); fastPointer=fastPointer.getnext().getnext(); } return slowPointer.getValue(); }
3.刪除具有相同值的節點(重復節點):
//刪除具有相同值的節點 //基本原理是用第一個節點的值和第二個節點值比較,然后和第三個節點比較,以此類推。此時第一個節點為當前節點nodeCur,第二第三以及之后的節點為比較節點compareNode //一輪比較完畢后,第二個節點就變成nodeCur,之后那些節點就是compareNode //如果遇到有相同的值的節點,就將該節點的上個節點的next值為該節點的下個節點:lastNode.setNext(compareNode.getnext()),此時該節點就在鏈表里失去引用了,就相當於刪除了。 //所以需要lastNode引用來保存當前比較節點的上一個節點 public void deleteDuplicateNode(){ Node nodeCur=head.getnext(); if(nodeCur==null) return; while(nodeCur.getnext()!=null){ Node lastNode=nodeCur; Node compareNode=lastNode.getnext(); while(compareNode!=null){ if(nodeCur.getValue().equals(compareNode.getValue())){ lastNode.setNext(compareNode.getnext()); compareNode=compareNode.getnext(); }else{ lastNode=compareNode; compareNode=compareNode.getnext(); } } nodeCur=nodeCur.getnext(); } }
寫好之后可以測試一下:
public class Test { public static void main(String[] args) { MyLinkedTable m=new MyLinkedTable(); m.add("1"); m.add("2"); m.add("3"); m.add("4"); m.add("5"); m.add("6"); for(int i=1;i<=m.length();i++){ System.out.println(i+":"+m.get(i)); } System.out.println("length:"+m.length()); m.reverseTable(); for(int i=1;i<=m.length();i++){ System.out.println(i+":"+m.get(i)); } System.out.println("length:"+m.length()); m.delete(2); for(int i=1;i<=m.length();i++){ System.out.println(i+":"+m.get(i)); } System.out.println("length:"+m.length()); System.out.println(m.getMid()); } }
運行輸出如下:
1:1
2:2
3:3
4:4
5:5
6:6
length:6
1:6
2:5
3:4
4:3
5:2
6:1
length:6
1:6
2:4
3:3
4:2
5:1
length:5
3
還有測試刪除重復節點的:
public class Test2 { public static void main(String[] args) { MyLinkedTable m=new MyLinkedTable(); m.add("1"); m.add("2"); m.add("3"); m.add("2"); m.add("2"); m.add("6"); for(int i=1;i<=m.length();i++){ System.out.println(i+":"+m.get(i)); } System.out.println("length:"+m.length()); m.deleteDuplicateNode(); for(int i=1;i<=m.length();i++){ System.out.println(i+":"+m.get(i)); } System.out.println("length:"+m.length()); } }
運行輸出:
1:1
2:2
3:3
4:2
5:2
6:6
length:6
1:1
2:2
3:3
4:6
length:4
以上就是用java實現單向無環鏈表的詳細過程和解釋,如果不妥之處,歡迎指出。