1. 程式人生 > >資料結構(五)——線性結構之連結串列Linked List

資料結構(五)——線性結構之連結串列Linked List

一.連結串列

典型的連結串列結構,連結串列中每個結點都應該包括如下內容:

  • 資料部分,儲存的是該結點的實際資料;
  • 地址部分,儲存的是下一個結點的地址。

由於採用了引用來指示下一個資料的地址。因此在連結串列結構中,邏輯上相鄰的結點在記憶體中不一定相鄰,邏輯相鄰關係通過地址部分的引用變數來實現。

(1)連結串列優點:

         連結串列最大的好處是結點之間不要求連續存放,因此在儲存大量資料的同時,不需要分配一塊連續的儲存空間。

         使用者可以用new函式動態分配結點的儲存空間,當刪除某個結點時,給該結點賦值null,釋放其佔用的記憶體空間。

(2)連結串列缺點:

         浪費儲存空間。對於每個結點資料,都要額外儲存一個引用變數。

(3)連結串列訪問方式:

         從表頭逐個查詢,即通過head頭引用找到第一個結點,再從第一個結點找到第二個結點....這樣逐個比較一直找到需要的結點為止。而不能像順序表一樣隨機訪問。

二.單鏈表

1.單鏈表定義

單向連結串列(又名單鏈表、線性連結串列)是連結串列的一種,其特點是連結串列的連結方向是單向的(每個結點中只包含一個引用),對連結串列的訪問要通過從頭部開始,依序往下讀取。

2.單鏈表的操作

單鏈表的主要操作有以下幾個:

(1)在連結串列結尾追加結點;

(2)獲取下一個結點;

(3)獲取最後一個結點;

(4)判斷當前結點是否為最後結點;

(5)刪除下一個結點;

(6)展示連結串列的所有結點;

(7)插入一個結點作為當前結點的下一個結點。

package cn.kimtian.linkedlist;

/**
 * 這是連結串列的一個結點
 *
 * @author kimtian
 */
public class Node {

    /**
     * 結點內容(存任何型別都可以)
     */
    private int data;

    /**
     * 下一個結點
     */
    Node next;

    /**
     * 建立結點的時候,給一個value
     *
     * @param data
     */
    public Node(int data) {
        this.data = data;
    }

    /**
     * 為結點追加結點(在連結串列的結尾)
     *
     * @param node
     */
    public Node appendNode(Node node) {
        //開始是當前結點
        Node currentNode = this;
        //迴圈向後找
        while (true) {
            //取出下一個節點,賦值給當前結點
            Node nextNode = currentNode.next;
            //結束標記,如果下一個結點為null,當前結點已經是最後一個結點了
            if (nextNode == null) {
                break;
            }
            currentNode = nextNode;
        }
        //把需要追加的結點追加到找到的當前結點的下一個結點
        currentNode.next = node;
        //將自身返回出去
        return this;
    }

    /**
     * 獲取結點的下一個結點
     */
    public Node nodeNext() {
        return this.next;
    }

    public int getData() {
        return this.data;
    }

    /**
     * 獲取結點的最終結點
     */
    public Node nodeFinal() {
        //開始是當前結點
        Node currentNode = this;
        //迴圈向後找
        while (true) {
            //取出下一個節點,賦值給當前結點
            Node nextNode = currentNode.next;
            //結束標記,如果下一個結點為null,當前結點已經是最後一個結點了
            if (nextNode == null) {
                break;
            }
            currentNode = nextNode;
        }
        //將自身返回出去
        return currentNode;
    }

    /**
     * 判斷當前結點是否為最後結點
     */
    public boolean isLast() {
        return this.next == null;
    }

    /**
     * 刪除下一個結點
     */
    public void removeNext() {
        //取出下下一個結點
        Node newNext = next.next;
        //把下下一個結點設定為當前結點的下一個結點
        this.next = newNext;
    }

    /**
     * 插入一個結點作為當前結點的下一個結點(在連結串列中間)
     *
     * @param node 插入的結點
     */
    public void addNode(Node node) {
        //取出下一個結點作為下下一個結點
        Node nextNode = next;
        //把新結點插入為當前結點的下一個結點
        this.next = node;
        //把下下一個結點設定為新結點的下一個結點
        node.next = nextNode;
    }

    /**
     * 顯示所有結點資訊
     */
    public void showNodes() {
        Node currentNode = this;
        while (true) {
            System.out.print(currentNode.data + " ");
            //取出下一個結點
            currentNode = currentNode.next;
            //如果是最後一個結點
            if (currentNode == null) {
                break;
            }
        }
        System.out.println();
    }
}

三.迴圈連結串列

1.單向迴圈連結串列定義:

   操作和單鏈表基本一致。(在單鏈表中,將終端結點的引用域null改為指向表頭結點或開始結點即可構成單迴圈連結串列。)

   只是它的最後一個結點指向頭結點,形成一個環。因此,從迴圈連結串列中的任何一個結點出發都能找到任何其他結點。

 

2.單向迴圈連結串列的操作:

(1)插入結點;

(2)刪除結點。

package cn.kimtian.linkedlist;

/**
 * 迴圈連結串列
 *
 * @author kimtian
 */
public class LoopNode {

    /**
     * 結點內容(存任何型別都可以)
     */
    private int data;

    /**
     * 下一個結點
     */
    LoopNode next = this;

    /**
     * 建立結點的時候,給一個value
     *
     * @param data
     */
    public LoopNode(int data) {
        this.data = data;
    }


    /**
     * 獲取結點的下一個結點
     */
    public LoopNode nodeNext() {
        return this.next;
    }

    public int getData() {
        return this.data;
    }

    /**
     * 刪除下一個結點
     */
    public void removeNext() {
        //取出下下一個結點
        LoopNode newNext = next.next;
        //把下下一個結點設定為當前結點的下一個結點
        this.next = newNext;
    }

    /**
     * 插入一個結點作為當前結點的下一個結點(在連結串列中間)
     *
     * @param node 插入的結點
     */
    public void addNode(LoopNode node) {
        //取出下一個結點作為下下一個結點
        LoopNode nextNode = next;
        //把新結點插入為當前結點的下一個結點
        this.next = node;
        //把下下一個結點設定為新結點的下一個結點
        node.next = nextNode;
    }

}

3.雙向迴圈連結串列定義

若每個結點包含兩個引用,一個指向下一個結點,另一個指向上一個結點,這就是雙向連結串列。

4.雙向連結串列操作

(1)增加一個結點;

(2)獲取上一個結點;

(3)獲取下一個結點;

package cn.kimtian.linkedlist;

/**
 * 這是一個雙向連結串列
 *
 * @author kimtian
 */
public class DoubleNode {
    /**
     * 結點內容(存任何型別都可以)
     */
    private int data;

    public int getData() {
        return data;
    }

    /**
     * 上一個結點
     */
    DoubleNode preDoubleNode = this;
    /**
     * 下一個結點
     */
    DoubleNode nextDoubleNode = this;

    /**
     * 建立結點的時候,給一個value
     *
     * @param data
     */
    public DoubleNode(int data) {
        this.data = data;
    }

    /**
     * 增加一個結點
     *
     * @param doubleNode 結點
     */
    public void addDoubleNode(DoubleNode doubleNode) {

        //取出下一個結點作為下下一個結點
        DoubleNode nextNode = nextDoubleNode;
        //把新結點插入為當前結點的下一個結點
        this.nextDoubleNode = doubleNode;
        //把當前結點作為新結點的前一個結點
        doubleNode.preDoubleNode = this;
        //把下下一個結點設定為新結點的下一個結點
        doubleNode.nextDoubleNode = nextNode;
        //把下下一個結點的上一個結點設定為新結點
        nextNode.preDoubleNode = doubleNode;
    }

    /**
     * 獲取下一個結點的方法
     */
    public DoubleNode getNext() {
        return this.nextDoubleNode;
    }

    /**
     * 獲取上一個結點的方法
     */
    public DoubleNode getPre() {
        return this.preDoubleNode;
    }
}

5.多重鏈的迴圈連結串列:

如果將表中的結點鏈在多個環上,將構成多重鏈的迴圈連結串列。