1. 程式人生 > >java實現--單向連結串列的插入和刪除

java實現--單向連結串列的插入和刪除

一、連結串列結構: (物理儲存結構上不連續,邏輯上連續;大小不固定)           

概念:

  鏈式儲存結構是基於指標實現的。我們把一個數據元素和一個指標稱為結點

        資料域:存數資料元素資訊的域。

        指標域:儲存直接後繼位置的域。

鏈式儲存結構是用指標把相互直接關聯的結點(即直接前驅結點或直接後繼結點)連結起來。鏈式儲存結構的線性表稱為連結串列

連結串列型別:

  根據連結串列的構造方式的不同可以分為:

  • 單向連結串列
  • 單向迴圈連結串列
  • 雙向迴圈連結串列

二、單鏈表:

概念:

連結串列的每個結點中只包含一個指標域,叫做單鏈表(即構成連結串列的每個結點只有一個指向直接後繼結點的指標


單鏈表中每個結點的結構:

912d954f-de3f-4d35-bd01-3c4f87d9993b

1、頭指標和頭結點:

單鏈表有帶頭結點結構不帶頭結點結構兩種。

“連結串列中第一個結點的儲存位置叫做頭指標”,如果連結串列有頭結點,那麼頭指標就是指向頭結點的指標

頭指標所指的不存放資料元素的第一個結點稱作頭結點(頭結點指向首元結點)。頭結點的資料域一般不放資料(當然有些情況下也可存放連結串列的長度、用做監視哨等)

存放第一個資料元素的結點稱作第一個資料元素結點,或稱首元結點

如下圖所示:

5fdb1362-fd98-4d23-9932-271f2ab9d480

不帶頭結點的單鏈表如下:

14c9aae5-c9fc-4dbe-b5c4-29c05ed84c5e

帶頭結點的單鏈表如下圖:

a9afd20d-da0f-4c59-a2d6-d8eb8175933b

關於頭指標和頭結點的概念區分,可以參考如下部落格:

2、不帶頭結點的單鏈表的插入操作:

912a8385-5a98-48b8-a515-8dfd9347042d

上圖中,是不帶頭結點的單鏈表的插入操作。如果我們在非第一個結點前進行插入操作,只需要a(i-1)的指標域指向s,然後將s的指標域指向a(i)就行了;如果我們在第一個結點前進行插入操作,頭指標head就要等於新插入結點s

,這和在非第一個資料元素結點前插入結點時的情況不同。另外,還有一些不同情況需要考慮。

因此演算法對這兩種情況就要分別設計實現方法

3、帶頭結點的單鏈表的插入操作:(操作統一,推薦)

95b7d67d-ddaa-4b00-99f6-c1acf4f708b1

上圖中,如果採用帶頭結點的單鏈表結構,演算法實現時,p指向頭結點,改變的是p指標的next指標的值(改變頭結點的指標域),而頭指標head的值不變

因此,演算法實現方法比較簡單,其操作與對其它結點的操作統一

問題1:頭結點的好處:

  頭結點即在連結串列的首元結點之前附設的一個結點,該結點的資料域中不儲存線性表的資料元素,其作用是為了對連結串列進行操作時,可以對空表、非空表的情況以及對首元結點進行統一處理,程式設計更方便。

問題2:如何表示空表:

  無頭結點時,當頭指標的值為空時表示空表;
  有頭結點時,當頭結點的指標域為空時表示空表。

如下圖所示:

問題3:頭結點的資料域內裝的是什麼?

頭結點的資料域可以為空,也可存放線性表長度等附加資訊,但此結點不能計入連結串列長度值

三、單項鍊表的程式碼實現

1、結點類:

編寫一個Node類來充當結點的模型。我們知道,其中有兩個屬性,1存放資料的data,2存放下一結點的引用,

public class Node {
    //為了方便,這兩個變數都使用public,而不用private就不需要編寫get、set方法了。
    //存放資料的變數,簡單點,直接為int型
    public int data;
    //存放結點的變數,預設為null
    public Node next;
    
    //構造方法,在構造時就能夠給data賦值
    public Node(int data){
        this.data = data;
    }
}
 單鏈表的簡單操作(增加,刪除,獲取總長度,連結串列元素排序,連結串列遍歷)

1.1增加結點操作,addNode(Node)

 /**
     * 增加操作
     *         直接在連結串列的最後插入新增的結點即可
     *         將原本最後一個結點的next指向新結點
     */
    public void addNode(Node node){
        //連結串列中有結點,遍歷到最後一個結點
        Node temp = head;    //一個移動的指標(把頭結點看做一個指向結點的指標)
        while(temp.next != null){    //遍歷單鏈表,直到遍歷到最後一個則跳出迴圈。
            temp = temp.next;        //往後移一個結點,指向下一個結點。
        }
        temp.next = node;    //temp為最後一個結點或者是頭結點,將其next指向新結點
    }
1.2插入結點到連結串列的指定位置。 insertNodeByIndex(int index,Node node)
/**
     * insertNodeByIndex:在連結串列的指定位置插入結點。
     *         插入操作需要知道1個結點即可,當前位置的前一個結點
     * index:插入連結串列的位置,從1開始
     * node:插入的結點
     */
    public void insertNodeByIndex(int index,Node node){
        //首先需要判斷指定位置是否合法,
        if(index<1||index>length()+1){
            System.out.println("插入位置不合法。");
            return;
        }
        int length = 1;            //記錄我們遍歷到第幾個結點了,也就是記錄位置。
        Node temp = head;        //可移動的指標
        while(head.next != null){//遍歷單鏈表
            if(index == length++){        //判斷是否到達指定位置。
                //注意,我們的temp代表的是當前位置的前一個結點。
                //前一個結點        當前位置        後一個結點
                //temp            temp.next     temp.next.next
                //插入操作。
                node.next = temp.next;            
                temp.next = node;                
                return;
            }
            temp = temp.next;
        }
    }

1.3刪除指定位置上的結點  delNodeByIndex(int index)

 /**
     * 通過index刪除指定位置的結點,跟指定位置增加結點是一樣的,先找到準確位置。然後進行刪除操作。
     *             刪除操作需要知道1個結點即可:和當前位置的前一個結點。
     * @param index:連結串列中的位置,從1開始
     * 
     */
    public void delNodeByIndex(int index){
        //判斷index是否合理
        if(index<1 || index>length()){
            System.out.println("給定的位置不合理");
            return;
        }

        //步驟跟insertNodeByIndex是一樣的,只是操作不一樣。    
        int length=1;
        Node temp = head;
        while(temp.next != null){
            if(index == length++){
                //刪除操作。
                temp.next = temp.next.next;    
                return;
            }
            temp = temp.next;
        }    
    }

1.4計算單鏈表的長度

/**
     * 計算單鏈表的長度,也就是有多少個結點
     * @return    結點個數
     */
    public int length() {
        int length=0;
        Node temp = head;
        while(temp.next != null){
            length++;
            temp = temp.next;
        }
        return length;
    }

1.5遍歷單鏈表,列印data

/**
     * 遍歷單鏈表,列印所有data
     */
    public void print(){
        Node temp = head.next;
        while(temp != null){
            System.out.print(temp.data+",");
            temp = temp.next;
        }
        System.out.println();
    }