Java實現單向鏈表基本功能

1、前言

最近在回顧數據結構與算法,有部分的算法題用到了棧的思想,提及棧又不得不說鏈表了。數組和鏈表都是線性存儲結構的基礎,棧和隊列都是線性存儲結構的應用~html

本文主要講解單鏈表的基礎知識點,作一個簡單的入門~若是有錯的地方請指正java

2、回顧與知新

提及鏈表,咱們先提一下數組吧,跟數組比較一下就很理解鏈表這種存儲結構了。算法

2.1回顧數組

數組咱們不管是C、Java都會學過:數組

  • 數組是一種連續存儲線性結構,元素類型相同,大小相等

數組的優勢:微信

  • 存取速度快

數組的缺點:數據結構

  • 事先必須知道數組的長度
  • 插入刪除元素很慢
  • 空間一般是有限制的
  • 須要大塊連續的內存塊
  • 插入刪除元素的效率很低

2.2鏈表說明

看完了數組,回到咱們的鏈表:this

  • 鏈表是離散存儲線性結構

n個節點離散分配,彼此經過指針相連,每一個節點只有一個前驅節點,每一個節點只有一個後續節點,首節點沒有前驅節點,尾節點沒有後續節點。spa

鏈表優勢:.net

  • 空間沒有限制
  • 插入刪除元素很快

鏈表缺點:指針

  • 存取速度很慢

鏈表相關術語介紹,我仍是經過上面那個圖來講明吧:

肯定一個鏈表咱們只須要頭指針,經過頭指針就能夠把整個鏈表都能推導出來了~

鏈表又分了好幾類:

  • 單向鏈表
    • 一個節點指向下一個節點
  • 雙向鏈表
    • 一個節點有兩個指針域
  • 循環鏈表
    • 能經過任何一個節點找到其餘全部的節點,將兩種(雙向/單向)鏈表的最後一個結點指向第一個結點從而實現循環

操做鏈表要時刻記住的是:

  • 節點中指針域指向的就是一個節點了!

3、Java實現鏈表

算法:

  • 遍歷
  • 查找
  • 清空
  • 銷燬
  • 求長度
  • 排序
  • 刪除節點
  • 插入節點

ps:我將head節點定義在成員變量上:

private static Node head = new Node();
複製代碼

首先,咱們定義一個類做爲節點

  • 數據域
  • 指針域

爲了操做方便我就直接定義成public了。

public class Node {

    //數據域
    public Integer data;
    
    //指針域,指向下一個節點
    public Node next;

    public Node() {
    }

    public Node(int data) {
        this.data = data;
    }

    public Node(int data, Node next) {
        this.data = data;
        this.next = next;
    }
}
複製代碼

3.1建立鏈表(增長節點)

向鏈表中插入數據:

  • 找到尾節點進行插入
  • 即便頭節點.next爲null,不走while循環,也是將頭節點與新節點鏈接的(我已經將head節點初始化過了,所以不必判斷頭節點是否爲null)~
/** * 向鏈表添加數據 * * @param value 要添加的數據 */
    public static void addData(int value) {

        //初始化要加入的節點
        Node newNode = new Node(value);

        //臨時節點
        Node temp = head;

        // 找到尾節點
        while (temp.next != null) {
            temp = temp.next;
        }

        // 已經包括了頭節點.next爲null的狀況了~
        temp.next = newNode;

    }

複製代碼

3.2遍歷鏈表

上面咱們已經編寫了增長方法,如今遍歷一下看一下是否正確~~~

從首節點開始,不斷日後面找,直到後面的節點沒有數據:

/** * 遍歷鏈表 * * @param head 頭節點 */
    public static void traverse(Node head) {

        
        //臨時節點,從首節點開始
        Node temp = head.next;

        while (temp != null) {

            if (temp.data != null) {
                System.out.println("關注公衆號Java3y:" + temp.data);
            }

            //繼續下一個
            temp = temp.next;
        }
    }
複製代碼

結果:

3.3插入節點

  1. 插入一個節點到鏈表中,首先得判斷這個位置是不是合法的,才能進行插入~
  2. 找到想要插入的位置的上一個節點就能夠了
/** * 插入節點 * * @param head 頭指針 * @param index 要插入的位置 * @param value 要插入的值 */
    public static void insertNode(Node head, int index, int value) {


        //首先須要判斷指定位置是否合法,
        if (index < 1 || index > linkListLength(head) + 1) {
            System.out.println("插入位置不合法。");
            return;
        }

        //臨時節點,從頭節點開始
        Node temp = head;

        //記錄遍歷的當前位置
        int currentPos = 0;

        //初始化要插入的節點
        Node insertNode = new Node(value);

        while (temp.next != null) {

            //找到上一個節點的位置了
            if ((index - 1) == currentPos) {

                //temp表示的是上一個節點

                //將本來由上一個節點的指向交由插入的節點來指向
                insertNode.next = temp.next;

                //將上一個節點的指針域指向要插入的節點
                temp.next = insertNode;

                return;

            }

            currentPos++;
            temp = temp.next;
        }

    }
複製代碼

3.4獲取鏈表的長度

獲取鏈表的長度就很簡單了,遍歷一下,每獲得一個節點+1便可~

/** * 獲取鏈表的長度 * @param head 頭指針 */
    public static int linkListLength(Node head) {

        int length = 0;

        //臨時節點,從首節點開始
        Node temp = head.next;

        // 找到尾節點
        while (temp != null) {
            length++;
            temp = temp.next;
        }

        return length;
    }
複製代碼

3.5刪除節點

刪除某個位置上的節點實際上是和插入節點很像的, 一樣都要找到上一個節點。將上一個節點的指針域改變一下,就能夠刪除了~

/** * 根據位置刪除節點 * * @param head 頭指針 * @param index 要刪除的位置 */
    public static void deleteNode(Node head, int index) {


        //首先須要判斷指定位置是否合法,
        if (index < 1 || index > linkListLength(head) + 1) {
            System.out.println("刪除位置不合法。");
            return;
        }

        //臨時節點,從頭節點開始
        Node temp = head;

        //記錄遍歷的當前位置
        int currentPos = 0;


        while (temp.next != null) {

            //找到上一個節點的位置了
            if ((index - 1) == currentPos) {

                //temp表示的是上一個節點

                //temp.next表示的是想要刪除的節點

                //將想要刪除的節點存儲一下
                Node deleteNode = temp.next;

                //想要刪除節點的下一個節點交由上一個節點來控制
                temp.next = deleteNode.next;


                //Java會回收它,設置不設置爲null應該沒多大意義了(我的以爲,若是不對請指出哦~)
                deleteNode = null;

                return;

            }
            currentPos++;
            temp = temp.next;
        }
    }
複製代碼

3.6對鏈表進行排序

前面已經講過了8種的排序算法了【八種排序算法總結】,此次挑簡單的冒泡排序吧(其實我是想寫快速排序的,嘗試了一下感受有點難.....)

/** * 對鏈表進行排序 * * @param head * */
    public static void sortLinkList(Node head) {


        Node currentNode;

        Node nextNode;

        for (currentNode = head.next; currentNode.next != null; currentNode = currentNode.next) {

            for (nextNode = head.next; nextNode.next != null; nextNode = nextNode.next) {


                if (nextNode.data > nextNode.next.data) {

                    int temp = nextNode.data;
                    nextNode.data = nextNode.next.data;

                    nextNode.next.data = temp;

                }
            }


        }
    }
複製代碼

3.7找到鏈表中倒數第k個節點

這個算法挺有趣的:設置兩個指針p一、p2,讓p2比p1快k個節點,同時向後遍歷,當p2爲空,則p1爲倒數第k個節點

/** * 找到鏈表中倒數第k個節點(設置兩個指針p一、p2,讓p2比p1快k個節點,同時向後遍歷,當p2爲空,則p1爲倒數第k個節點 * * @param head * @param k 倒數第k個節點 */
    public static Node findKNode(Node head, int k) {

        if (k < 1 || k > linkListLength(head))
            return null;
        Node p1 = head;
        Node p2 = head;

        // p2比怕p1快k個節點
        for (int i = 0; i < k - 1; i++)
            p2 = p2.next;


        // 只要p2爲null,那麼p1就是倒數第k個節點了
        while (p2.next != null) {

            p2 = p2.next;
            p1 = p1.next;
        }
        return p1;


    }
複製代碼

3.8刪除鏈表重複數據

這裏以前有問題,你們能夠到:blog.csdn.net/ifollowrive…

進行參考

3.9查詢鏈表的中間節點

這個算法也挺有趣的:一個每次走1步,一個每次走兩步,走兩步的遍歷完,而後走一步的指針,那就是中間節點

/** * 查詢單鏈表的中間節點 */

    public static Node searchMid(Node head) {

        Node p1 = head;
        Node p2 = head;


        // 一個走一步,一個走兩步,直到爲null,走一步的到達的就是中間節點
        while (p2 != null && p2.next != null && p2.next.next != null) {

            p1 = p1.next;
            p2 = p2.next.next;

        }

        return p1;


    }
複製代碼

3.10經過遞歸從尾到頭輸出單鏈表

/** * 經過遞歸從尾到頭輸出單鏈表 * * @param head 頭節點 */
    public static void printListReversely(Node head) {
        if (head != null) {
            printListReversely(head.next);
            if (head.data != null) {
                System.out.println(head.data);
            }
        }
    }
複製代碼

3.11反轉鏈表

/** * 實現鏈表的反轉 * * @param head 鏈表的頭節點 */
    public static Node reverseList(Node head) {

        Node pre = null;
        Node cur = head;
        while (cur != null) {
            Node next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }

        return pre;
    }
  // 翻轉完,使用下面的代碼進行遍歷吧:
  public static void traverse4Reverse(Node head) {

        //臨時節點,從首節點開始
        Node temp = head;

        while (temp != null) {

            if (temp.data != null) {
                System.out.println("關注公衆號Java3y:" + temp.data);
            }

            //繼續下一個
            temp = temp.next;
        }
    }
複製代碼

反轉鏈表參考自:

4、最後

理解鏈表自己並不難,但作相關的操做就弄得頭疼,head.next next next next ....(算法這方面我仍是薄弱啊..腦子不夠用了.....)寫了兩天就寫了這麼點東西...

操做一個鏈表只須要知道它的頭指針就能夠作任何操做了

  • 添加數據到鏈表中
    • 遍歷找到尾節點,插入便可(只要while(temp.next != null),退出循環就會找到尾節點)
  • 遍歷鏈表
    • 從首節點(有效節點)開始,只要不爲null,就輸出
  • 給定位置插入節點到鏈表中
    • 首先判斷該位置是否有效(在鏈表長度的範圍內)
    • 找到想要插入位置的上一個節點
      • 將本來由上一個節點的指向交由插入的節點來指向
      • 上一個節點指針域指向想要插入的節點
  • 獲取鏈表的長度
    • 每訪問一次節點,變量++操做便可
  • 刪除給定位置的節點
    • 首先判斷該位置是否有效(在鏈表長度的範圍內)
    • 找到想要插入位置的上一個節點
      • 將本來由上一個節點的指向後面一個節點
  • 對鏈表進行排序
    • 使用冒泡算法對其進行排序
  • 找到鏈表中倒數第k個節點
    • 設置兩個指針p一、p2,讓p2比p1快k個節點,同時向後遍歷,當p2爲空,則p1爲倒數第k個節點
  • 刪除鏈表重複數據
    • 操做跟冒泡排序差很少,只要它相等,就能刪除了
  • 查詢鏈表的中間節點
    • 這個算法也挺有趣的:一個每次走1步,一個每次走兩步,走兩步的遍歷完,而後走一步的指針,那就是中間節點
  • 遞歸從尾到頭輸出單鏈表
    • 只要下面還有數據,那就往下找,遞歸是從最後往前翻
  • 反轉鏈表
    • 有遞歸和非遞歸兩種方式,我以爲是挺難的。能夠到我給出的連接上查閱~

PS:每一個人的實現都會不同,因此一些小細節不免會有些變更,也沒有固定的寫法,可以實現對應的功能便可~

參考資料:

若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y

相關文章
相關標籤/搜索