數據結構與算法_鏈表1_單鏈表

鏈表可能是繼數組之後第二種使用最爲廣泛的數據結構。

鏈表有單鏈表、雙端鏈表、有序鏈表、雙向鏈表。本文講的就是鏈表中的基本即單鏈表,來了解鏈表的基本操作和概念。


通過下圖簡單瞭解鏈表的概念



其特點舉個簡單例子,如圖把33這個元素插入在42之前,數組實現的話要把42開始之後爲元素全部後移一位,然後把33插到指定位置,然而鏈表則可以隨便的把他分配在某一個位置,然後我們通過修改指針關係,把散落在各個位置的單元串聯起來,把原來指向42的指針指向33,並把33的下一個指針指向42僅僅這2步動作就完成了把33這個新單元加入到我們的鏈表中,並且後面這些元素7 98等根本沒有感受到這個插入動作,對他們沒有任何影響。

這樣內存的分配比較靈活,可以隨意的分配。


刪除的時候同理。要把33這個單元刪除,只要把指向它的那個指針再指向42就可以了,其他的什麼都不需要動,注意此時的33單元沒有任何指針指向它,現在它變成了垃圾對象,將來會被系統回收。然而單鏈表的隨機訪問很慢,要從head找到第一個元素然後找找找。。

還有兩個概念即鏈結點和鏈表類;

上圖中的每一項都是鏈結點,一個鏈結點是某個類的對象,這個類可以叫做Link。因爲一個鏈表中有許多類似的鏈結點,所以有必要用一個不同於鏈表的類來表達鏈結點。每個Link對象中都包含一個對下一個鏈結點引用的字段(通常叫做next),但是鏈表本身的對象中有一個字段指向對第一個鏈結點的引用。

鏈表:LinkList類中只包含一個數據項:即對鏈表中第一個鏈結點的引用,叫做head。他是唯一的鏈表需要維護的永久信息,用以定位所有其他的鏈結點。從head出發,沿着鏈表通過每個鏈結點的next字段,就可以找到其他的鏈結點。


實現的代碼如下:

public class YezhuLinkedList {
    public Link head = null;

    public boolean isEmpty() {
        return head == null;
    }

    /**
     * insertFirst() 作用是在表頭插入一個新鏈結點。實際上,這是最容
     * 易插入的一個鏈結點。具體操作時,新創建的鏈結點的next指向原來
     * head指向的值,然後head指向新插入的鏈結點。
     */
    public void insertFirst(int a) {
        Link link = new Link(a);
        link.next = head; //新插入的元素 指向原來head指向的鏈接點
        head = link;//head指向新插入的元素
    }

    /**
     * 展示全部的結點數據
     */
    public void showAll() {
        //從head開始遍歷 到最後一個元素的時候 指向的肯定是空
        Link current = head;
        while (current != null) {
            System.out.println(current.data);
            current = current.next;
        }
    }

    /**
     * 在尾部插入元素
     * 從頭開始一直遍歷 遍歷到尾部 讓之前Link的next指向新的結點
     */
    public void insertLast(int data) {
        Link link = new Link(data);

        if (head == null) {
            link.next = head;
            head = link;
        } else {

            Link current = head;
            while (current.next != null) {
                current = current.next;
            }

            current.next = link;
        }


    }

    /**
     * 刪除頭元素
     */
    public void deleteFirst() {
        Link current = head;
        head = current.next;
    }

    /**
     * 長度
     *
     * @return
     */
    public int length() {
        int length = 0;
        Link link = head;
        while (link != null) {
            length++;
            link = link.next;
        }
        return length;
    }

    /**
     * 根據元素的關鍵字 找到其結點所在的位置
     *
     * @param data
     * @return
     */
    public int getPosByValue(int data) {
        Link current = head;
        int position = 0;

        if (!contains(data)) {
            return -1;
        } else {
            while (current.data != data) {

                position++;
                if (current.next == null) {
                    return position;
                } else {
                    current = current.next;
                }
            }
            return position;
        }
    }

    /**
     * 整個鏈表中是否包含關鍵字爲data的鏈結點
     *
     * @param data
     * @return
     */
    public boolean contains(int data) {
        Link current = head;
        int position = 0;
        while (current.data != data && current.next != null) {
            //判斷條件加上current.next != null 是爲了隊尾的時候的空指針
            position++;
            current = current.next;
        }

        //遍歷到鏈表的尾部 要是position到了尾部 說明沒有包含此元素
        if (position == length() - 1) {
            return false;
        } else {
            return true;
        }
    }

}
 測試代碼:

/**
 * 測試
 */

public class Test {
    public static void main(String[] args) {
        YezhuLinkedList yezhuLinkedList = new YezhuLinkedList();

        yezhuLinkedList.insertFirst(1);
        yezhuLinkedList.insertFirst(5);

        yezhuLinkedList.insertLast(8);

        yezhuLinkedList.insertFirst(3);

        yezhuLinkedList.showAll();

        //測試是否包含關鍵字是data的鏈結點,有則輸出位置
        int data = 10;
        if (yezhuLinkedList.contains(data)) {
            System.out.println("包含此元素,在鏈表中的位置是:" + yezhuLinkedList.getPosByValue(data));
        } else {
            System.out.println("不包含此元素");
        }

//        yezhuLinkedList.deleteFirst();
        System.out.println("鏈表長度是" + yezhuLinkedList.length());
    }
}

輸出結果:



其過程中我們可以看到一個這樣的結構,能更清楚的瞭解鏈表的屬性結構:


顯然就是從head鏈結點一個指向一個的展開。


如上代碼如有問題請多多指出。


關於鏈結點補充:

1.鏈結點中的數據域可能包含很多的數據項,比如一個個人記錄可能有姓名、地址、社保號、頭銜等許多字段。通常用一個包含這些數據的類的對象來代替這些數據項。

2.可以讓每個鏈表的鏈結點是一個小型的數組,比如我們一個數組要表達十萬個這樣的數據,我們可以把每一百或一千個這樣的數組做成一個小單元,把這樣的小單元用鏈表串

聯起來,那麼它既有數組的結構又有鏈表的優點,也就是數據結構靈活的綜合的應用。

也就是說真實的鏈表在實際使用過程中有很多的變種,一定要靈活的選擇合適的機構。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章