Java 單向連結串列和單向迴圈連結串列的程式碼實現
阿新 • • 發佈:2019-01-07
這個連結串列,以前上學的時候,學c語言,還是資料結構的時候,學過。也許也實現過吧。下面我就簡單記錄下這個連結串列的實現。
單向連結串列跟單向迴圈連結串列的差別就是:單向連結串列是有結束位的,指向null的時候,就到結尾了,但是單向迴圈連結串列,他就是一個圈,要是不設定指定位置,他是會一直轉下去的,轉著轉著就會出現OOM異常了,也就是記憶體溢位啦。
單鏈表
先看單鏈表的節點物件--Node類。
這是組成連結串列的節點,就像一條鐵鏈上的每個鐵環一樣,一環扣一環,那這個鏈就出來啦。
package com.lxk.linkedList.oneWay; /** * Created by lxk on 2017/8/1 */ public class Node<K, V> { private final K key; private V value; private Node<K, V> next; public Node(K key, V value, Node<K, V> next) { this.key = key; this.value = value; this.next = next; } public K getKey() { return key; } public V getValue() { return value; } public void setValue(V value) { this.value = value; } public Node<K, V> getNext() { return next; } public void setNext(Node<K, V> next) { this.next = next; } }
要是看過hashmap原始碼的哥們,這個類就很好理解啦,其實也簡單,這個物件就三個屬性,一個k,一個v,一個next指標。
可能有個高階點的地方,就是這個類使用了泛型。泛型說高階也不算高階。
可以簡單理解為,我這個型別是根據傳進來的型別設定的也可以。
想深入透徹瞭解這個泛型相關知識的,可以看以下2個連結。
以上2篇文章,雖然是轉載的,但是,講的卻是極好的。
下面看對單鏈表的操作類--OneWayLinkedList類
package com.lxk.linkedList.oneWay; /** * 單向連結串列 * <p> * Created by lxk on 2017/8/1 */ public class OneWayLinkedList { /** * 獲得單向連結串列(頭插法生成的單向連結串列--後來的在連結串列頭部) */ public static Node<Integer, Integer> getOneWayLinkedList() { Node<Integer, Integer> temp = null; for (int i = 1; i <= 6; i++) { temp = new Node<>(i, i, temp);//頭插法:先來的在鏈尾 } return temp; } /** * 獲得單向連結串列(尾插法生成的單向連結串列--後來的鏈在連結串列尾部) */ public static Node<Integer, Integer> getOneWayLinkedListTail() { Node<Integer, Integer> headWillMove = new Node<>(1, 1, null); Node<Integer, Integer> headNoMove = headWillMove;//headWillMove,但是這個headNoMove是一直指向連結串列頭的。返回他就對了。 for (int i = 2; i <= 6; i++) { headWillMove.setNext(new Node<>(i, i, null));//尾插法:先來的在鏈頭 headWillMove = headWillMove.getNext(); } return headNoMove; } /** * 輸出單向連結串列 */ public static void forLinkedList(Node<Integer, Integer> linkedList) { StringBuilder sb = new StringBuilder(); sb.append("{"); while (linkedList != null) { sb.append("[k:").append(linkedList.getKey()).append(" v:").append(linkedList.getValue()).append("]"); linkedList = linkedList.getNext(); } sb.append("}"); System.out.println(sb.toString()); } /** * 獲得單向連結串列的最後一個節點 */ public static Node<Integer, Integer> getLastNode(Node<Integer, Integer> linkedList) { while (linkedList.getNext() != null) { linkedList = linkedList.getNext(); } return linkedList; } /** * 獲得連結串列的長度 */ public static int getOneWayLinkedListSize(Node<Integer, Integer> linkedList) { int size = 0; while (linkedList != null) { size++; linkedList = linkedList.getNext(); } return size; } /** * 在連結串列指定位置之後插入元素 */ public static void insertInLinkedList(int index, int key, int value, Node<Integer, Integer> linkedList) { int size = getOneWayLinkedListSize(linkedList); if (index < 0 || index >= size) { System.out.println("out of index bounds"); return; } for (int i = 0; i < size; i++) { if (index == i) { linkedList.setNext(new Node<>(key, value, linkedList.getNext())); break; } linkedList = linkedList.getNext(); } } /** * 在連結串列指定位置之後刪除節點 */ public static void removeInLinkedList(int index, Node<Integer, Integer> linkedList) { int size = getOneWayLinkedListSize(linkedList); if (index < 0 || index >= size) { System.out.println("out of index bounds"); return; } for (int i = 0; i < size; i++) { if (index == i) { if (linkedList.getNext() == null) { System.out.println("out of index bounds"); break; } linkedList.setNext(linkedList.getNext().getNext()); break; } linkedList = linkedList.getNext(); } } }
這個 類的每個方法,都寫了註釋,也就是簡單的對單向連結串列的一些簡單操作。
單向迴圈連結串列
這個單向迴圈連結串列,就是在單向連結串列的基礎上,把首尾給連起來,他就是迴圈連結串列了。
package com.lxk.linkedList.circularList; import com.lxk.linkedList.oneWay.Node; import com.lxk.linkedList.oneWay.OneWayLinkedList; /** * 迴圈連結串列 * <p> * Created by lxk on 2017/8/1 */ public class CircularOneWayList { /** * 獲得單向迴圈連結串列 * * @return 獲得單向迴圈連結串列,預設返回的就連結串列頭。 */ public static Node<Integer, Integer> getCircularOneWayList() { //獲得的單向連結串列的頭 Node<Integer, Integer> head = OneWayLinkedList.getOneWayLinkedListTail(); //找到這個連結串列的尾 Node<Integer, Integer> tail = OneWayLinkedList.getLastNode(head); //首尾相連,就成環了。 tail.setNext(head); return head; } /** * 獲得迴圈連結串列的長度(要想獲得長度,得設定個停止標記。) * * @param linkedList 單向迴圈連結串列,(必須是)連結串列頭的位置開始。 */ public static int getCircularLinkedListSize(Node<Integer, Integer> linkedList) { //注意:前提條件-->假設所有的值不重複,才能這麼幹。 int size = 1;//預設從1開始,迴圈到1時結束, linkedList = linkedList.getNext();//跨過key為1的節點,也就是把key為1的節點,作為標記。 while (linkedList.getKey() != 1) { size++; linkedList = linkedList.getNext(); } return size; } }
最後,看主測試程式碼
package com.lxk.linkedList;
import com.lxk.linkedList.oneWay.Node;
import static com.lxk.linkedList.circularList.CircularOneWayList.*;
import static com.lxk.linkedList.oneWay.OneWayLinkedList.*;
/**
* 連結串列測試
* <p>
* Created by lxk on 2017/8/1
*/
public class Main {
public static void main(String[] args) {
testOneWayLinkedList();//單向連結串列
testCircularOneWayList();//迴圈連結串列
}
/**
* 測試迴圈連結串列
*/
private static void testCircularOneWayList() {
Node<Integer, Integer> linkedList = getCircularOneWayList();//獲得初始化連結串列
//forLinkedList(linkedList);//列印
System.out.println(getCircularLinkedListSize(linkedList));
}
/**
* 測試單向連結串列
*/
private static void testOneWayLinkedList() {
Node<Integer, Integer> linkedList = getOneWayLinkedList();//獲得初始化連結串列---頭插法
//Node<Integer, Integer> linkedList = getOneWayLinkedListTail();//獲得初始化連結串列---尾插法
int size = getOneWayLinkedListSize(linkedList);
System.out.println("oneWayLinkedList's size:" + size);//連結串列長度
forLinkedList(linkedList);//列印
insertInLinkedList(5, 10, 10, linkedList);//在下標為5的節點之後插入
forLinkedList(linkedList);//列印
removeInLinkedList(5, linkedList);//在下標為5的節點之後刪除
forLinkedList(linkedList);//列印
}
}
看看迴圈連結串列的debug圖
再看下我的這幾個檔案是怎麼存放的。
上面的關於迴圈連結串列的方法寫的有點粗糙,沒寫完整。先湊合一下吧。