1. 程式人生 > >Java 單向連結串列和單向迴圈連結串列的程式碼實現

Java 單向連結串列和單向迴圈連結串列的程式碼實現

這個連結串列,以前上學的時候,學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圖


再看下我的這幾個檔案是怎麼存放的。


上面的關於迴圈連結串列的方法寫的有點粗糙,沒寫完整。先湊合一下吧。