1. 程式人生 > >資料結構之連結串列(LinkedList)(二)

資料結構之連結串列(LinkedList)(二)

資料結構之連結串列(LinkedList)(一)

雙鏈表

上一篇講述了單鏈表是通過next 指向下一個節點,那麼雙鏈表就是指不止可以順序指向下一個節點,還可以通過prior域逆序指向上一個節點

示意圖:

那麼怎麼來實現雙鏈表的增刪改查操作呢。

分析:

1) 遍歷 方和 單鏈表一樣,只是可以向前,也可以向後查詢

2) 新增 (預設新增到雙向連結串列的最後)

① 先找到雙向連結串列的最後這個節點

② temp.next = newStuNode

③ newStuNode.prior = temp;

3) 修改 思路和 原來的單向連結串列一樣.

4) 刪除

①因為是雙向連結串列,因此,我們可以實現自我刪除某個節點

② 直接找到要刪除的這個節點,比如temp

③ temp.prior.next = temp.next

④ temp.next.prior= temp.prior;

實現程式碼:

新增&遍歷:

預設新增在連結串列最後一個。

 // 新增一個節點到雙向連結串列的最後.
    public void  add(StuNode2 stuNode2){

        // 因為head節點不能動,因此我們需要一個輔助遍歷 temp
        StuNode2 temp = head;
        // 遍歷連結串列,找到最後
        while (true) {
            // 找到連結串列的最後
            if (temp.next == null) {//
                break;
            }
            // 如果沒有找到最後, 將將temp後移
            temp = temp.next;
        }
        // 當退出while迴圈時,temp就指向了連結串列的最後
        // 形成一個雙向連結串列
        temp.next = stuNode2;
        stuNode2.prior = temp;
    }
新增程式碼
//遍歷雙向列表的方法   和單項列表一致
    //顯示連結串列[遍歷]
    public void list() {
        //判斷連結串列是否為空
        if(head.next == null) {
            System.out.println("連結串列為空");
            return;
        }
        //因為頭節點,不能動,因此我們需要一個輔助變數來遍歷
        StuNode2 temp = head.next;
        while(true) {
            //判斷是否到連結串列最後
            if(temp == null) {
                break;
            }
            //輸出節點的資訊
            System.out.println(temp);
            //將temp後移, 一定小心
            temp = temp.next;
        }
    }
遍歷程式碼
public static void main(String[] args) {
        //進行測試
        //先建立節點
        StuNode2 stu1 = new StuNode2(1, "張三", "85");
        StuNode2 stu2 = new StuNode2(2, "李四", "87");
        StuNode2 stu3 = new StuNode2(3, "小明", "70");
        StuNode2 stu4 = new StuNode2(4, "小紅", "90");

        //建立要給連結串列
        DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
        //加入
        doubleLinkedList.add(stu1);
        doubleLinkedList.add(stu2);
        doubleLinkedList.add(stu3);
        doubleLinkedList.add(stu4);
        System.out.println("原始雙鏈表資料  " );
        doubleLinkedList.list();;
    }
main
原始雙鏈表資料  
StuNode [stuNo=1, name=張三, mark=85]
StuNode [stuNo=2, name=李四, mark=87]
StuNode [stuNo=3, name=小明, mark=70]
StuNode [stuNo=4, name=小紅, mark=90]
輸出

 根據序號排序新增

上面新增是預設新增到最後一個節點,那麼要求根據序號預設排序新增呢,其實和單鏈表是一樣思路

public  void addByOrder(StuNode2 stuNode2){
        StuNode2 temp = head;
        boolean flag = false;
        while (true){
            if (temp.next == null){
                break;
            }
            if (temp.next.stuNo>stuNode2.stuNo){//位置找到
                break;
            }else if (temp.stuNo == stuNode2.stuNo){
                flag=true;
                break;
            }
            temp =temp.next;
        }
        if (flag){
            System.out.printf("準備插入的學生 %d 已經存在了, 不能加入\n", stuNode2.stuNo);
        }else{
            stuNode2.next=temp.next;
            temp.next=stuNode2;
            stuNode2.prior=temp;
            if(temp.next != null){
                temp.next.prior=stuNode2;
            }
        }
    }
程式碼

修改:

// 修改一個節點的內容, 可以看到雙向連結串列的節點內容修改和單向連結串列一樣
    // 只是 節點型別改成 StuNode2
    public void update(StuNode2 newStuNode) {
        // 判斷是否空
        if (head.next == null) {
            System.out.println("連結串列為空~");
            return;
        }
        // 找到需要修改的節點, 根據stuNo編號
        // 定義一個輔助變數
        StuNode2 temp = head.next;
        boolean flag = false; // 表示是否找到該節點
        while (true) {
            if (temp == null) {
                break; // 已經遍歷完連結串列
            }
            if (temp.stuNo == newStuNode.stuNo) {
                // 找到
                flag = true;
                break;
            }
            temp = temp.next;
        }
        // 根據flag 判斷是否找到要修改的節點
        if (flag) {
            temp.name = newStuNode.name;
            temp.mark = newStuNode.mark;
        } else { // 沒有找到
            System.out.printf("沒有找到 學號 %d 的節點,不能修改\n", newStuNode.stuNo);
        }
    }
修改程式碼
public static void main(String[] args) {
        //進行測試
        //先建立節點
        StuNode2 stu1 = new StuNode2(1, "張三", "85");
        StuNode2 stu2 = new StuNode2(2, "李四", "87");
        StuNode2 stu3 = new StuNode2(3, "小明", "70");
        StuNode2 stu4 = new StuNode2(4, "小紅", "90");

        //建立要給連結串列
        DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
        //加入
        doubleLinkedList.add(stu1);
        doubleLinkedList.add(stu2);
        doubleLinkedList.add(stu3);
        doubleLinkedList.add(stu4);
        System.out.println("原始雙鏈表資料  " );
        doubleLinkedList.list();;
        //修改3號的分數
        StuNode2 stu = new StuNode2(3,"小明","99");
        doubleLinkedList.update(stu);
        System.out.println("修改後的連結串列");
        doubleLinkedList.list();;


    }
main
原始雙鏈表資料  
StuNode [stuNo=1, name=張三, mark=85]
StuNode [stuNo=2, name=李四, mark=87]
StuNode [stuNo=3, name=小明, mark=70]
StuNode [stuNo=4, name=小紅, mark=90]
修改後的連結串列
StuNode [stuNo=1, name=張三, mark=85]
StuNode [stuNo=2, name=李四, mark=87]
StuNode [stuNo=3, name=小明, mark=99]
StuNode [stuNo=4, name=小紅, mark=90]
輸出

 刪除:

上篇單鏈表的思路是找到要刪除節點的前一個節點,然後待刪除節點的前一個節點直接指向待刪除節點的後一個節點,隱藏待刪除的節點,從而達到刪除目的。

那麼雙鏈表可以直接找到待刪除節點temp,通過逆指向 temp.prior 找到待刪除節點的上一個節點,然後順指向temp.prior.next 指向待刪除節點的下一個節點temp.next

也就是 temp.prior.next = temp.next。同時要修改 待刪除節點的下一個節點的逆指向 指向待刪除節點的上一個節點,也就是temp.next.prior= temp.prior;

示意圖:

// 從雙向連結串列中刪除一個節點,
    // 說明
    // 1 對於雙向連結串列,我們可以直接找到要刪除的這個節點
    // 2 找到後,自我刪除即可
    public void del(int stuNo) {

        // 判斷當前連結串列是否為空
        if (head.next == null) {// 空連結串列
            System.out.println("連結串列為空,無法刪除");
            return;
        }

        StuNode2 temp = head.next; // 輔助變數(指標)
        boolean flag = false; // 標誌是否找到待刪除節點的
        while (true) {
            if (temp == null) { // 已經到連結串列的最後
                break;
            }
            if (temp.stuNo == stuNo) {
                // 找到的待刪除節點的前一個節點temp
                flag = true;
                break;
            }
            temp = temp.next; // temp後移,遍歷
        }
        // 判斷flag
        if (flag) { // 找到
            // 可以刪除
            // temp.next = temp.next.next;[單向連結串列]
            temp.prior.next = temp.next;
            // 如果是最後一個節點,就不需要執行下面這句話,否則出現空指標
            if (temp.next != null) {
                temp.next.prior = temp.prior;
            }
        } else {
            System.out.printf("要刪除的 %d 節點不存在\n", stuNo);
        }
    }
刪除程式碼
public static void main(String[] args) {
        //進行測試
        //先建立節點
        StuNode2 stu1 = new StuNode2(1, "張三", "85");
        StuNode2 stu2 = new StuNode2(2, "李四", "87");
        StuNode2 stu3 = new StuNode2(3, "小明", "70");
        StuNode2 stu4 = new StuNode2(4, "小紅", "90");

        //建立要給連結串列
        DoubleLinkedList doubleLinkedList = new DoubleLinkedList();
        //加入
        doubleLinkedList.add(stu1);
        doubleLinkedList.add(stu2);
        doubleLinkedList.add(stu3);
        doubleLinkedList.add(stu4);
        System.out.println("原始雙鏈表資料  " );
        doubleLinkedList.list();
        //刪除3號資料
        doubleLinkedList.del(3);
        System.out.println("刪除後的連結串列  " );
        doubleLinkedList.list();

    }
main
原始雙鏈表資料  
StuNode [stuNo=1, name=張三, mark=85]
StuNode [stuNo=2, name=李四, mark=87]
StuNode [stuNo=3, name=小明, mark=70]
StuNode [stuNo=4, name=小紅, mark=90]
刪除後的連結串列  
StuNode [stuNo=1, name=張三, mark=85]
StuNode [stuNo=2, name=李四, mark=87]
StuNode [stuNo=4, name=小紅, mark=90]
輸出

&n