首頁 > 軟體

Java資料結構之雙向連結串列的實現

2022-10-26 14:01:44

1 雙向連結串列

1.1 雙向連結串列介紹

相較單連結串列,雙向連結串列除了data與next域,還多了一個pre域用於表示每個節點的前一個元素。這樣做給雙向連結串列帶來了很多優勢:

單向連結串列查詢的方向只能是一個方向,而雙向連結串列可以向前或者向後查詢;

單連結串列如果想要實現刪除操作,需要找到待刪除節點的前一個節點。而雙向連結串列可以實現自我刪除。

雙向連結串列結構示意圖如下:

1.2 雙向連結串列實現思路

與單連結串列實現類似,交集部分不再贅述,詳情可參考文章:Java資料結構:單連結串列的實現與面試題彙總

遍歷:

與單連結串列遍歷方式一樣,同時,雙向連結串列可以支援向前和向後兩種查詢方式

新增:

新增到末尾

  • 先找到雙向連結串列最後一個節點
  • cur.next = newNode;
  • newNode.pre = cur;

按照no順序新增

  • 先判斷該連結串列是否為空,如果為空則直接新增
  • 如果不為空則繼續處理
  • 根據no遍歷連結串列,找到合適的位置
  • newNode.next = cur.next;
  • cur.next = newNode;
  • newNode.pre = cur;

修改操作與單連結串列實現步驟一致

刪除操作:

  • 雙向連結串列可以實現自我刪除
  • 直接找到待刪除的節點
  • cur.pre.next = cur.next;
  • cur.next.pre = cur.pre;
  • 需要特別注意是否為最後一個元素,如果為最後一個元素,cur.next為null,此時使用cur.next.pre會出現空指標異常,所以,如果為最後一個元素,則該步驟可以省略,cur.next為null即可。

以刪除紅色的2號節點為例:

2 雙向連結串列實現完整程式碼

2.1 節點類 Student.java

/**
 * @author 興趣使然黃小黃
 * @version 1.0
 * 學生類節點
 */
public class StudentNode {
    public String no; //學號
    public String name; //姓名
    public int age; //年齡
    public StudentNode pre; //指向前一個節點
    public StudentNode next; //指向下一個節點

    //構造器
    public StudentNode(String no, String name, int age ){
        this.no = no;
        this.name = name;
        this.age = age;
    }

    //為了顯示方便
    @Override
    public String toString() {
        return "StudentNode{" +
                "no='" + no + ''' +
                ", name='" + name + ''' +
                ", age=" + age +
                '}';
    }
}

2.2 雙向連結串列實現類 StudentDoubleLinkedList.java

/**
 * @author 興趣使然黃小黃
 * @version 1.0
 * 學生雙向連結串列的具體實現
 */
public class StudentDoubleLinkedList {
    //定義頭節點
    private StudentNode head = new StudentNode("", "", 0);

    //獲取頭節點
    public StudentNode getHead(){
        return head;
    }

    //遍歷雙向連結串列的方法
    public void showList(){
        //判斷連結串列是否為空
        if (head.next == null){
            System.out.println("當前連結串列為空");
            return;
        }
        //遍歷 使用輔助指標
        StudentNode temp = head;
        while (temp != null){
            //更新指標
            temp = temp.next;
            if (temp.next == null){
                System.out.print(temp);
                break;
            }
            System.out.print(temp + "--->");
        }
    }

    //新增節點的方法
    //新增到尾部
    public void add(StudentNode newNode){
        //先找到最後一個節點
        StudentNode cur = head;
        while (true){
            //到達最後退出迴圈
            if (cur.next == null){
                break;
            }
            //更新指標
            cur = cur.next;
        }
        //新增操作
        newNode.next = cur.next; //也可以省略,因為恆為null
        cur.next = newNode;
        newNode.pre = cur;
    }

    //新增節點的方法
    //根據學號順序新增
    public void addByOrder(StudentNode newNode){
        //如果當前連結串列為空,則直接新增
        if (head.next == null){
            head.next = newNode;
            newNode.pre = head;
            return;
        }
        //按照學號找到對應位置
        StudentNode cur = head;
        boolean flag = false; //標識待新增的no是否存在
        while (true){
            if (cur.next == null){
                //已經到達連結串列的尾部
                break;
            } else if (Integer.parseInt(cur.next.no) == Integer.parseInt(newNode.no)){
                //已經存在
                flag = true;
                break;
            }else if (Integer.parseInt(cur.next.no) > Integer.parseInt(newNode.no)){
                //位置找到
                break;
            }
            cur = cur.next;
        }
        if (flag){
            System.out.println("當前no已經存在,無法新增!");
        }else {
            //新增操作
            newNode.next = cur.next;
            cur.next = newNode;
            newNode.pre = cur;
        }
    }

    //根據no學號修改學生資訊
    public void update(StudentNode studentNode){
        if (head.next == null){
            System.out.println("當前連結串列為空, 無法修改");
            return;
        }
        StudentNode temp = head.next;
        boolean flag = false; //表示是否找到節點
        while (true){
            if (temp == null){
                break;
            }
            if (temp.no == studentNode.no){
                flag = true;
                break;
            }
            temp = temp.next;
        }
        if (flag){
            temp.name = studentNode.name;
            temp.age = studentNode.age;
            System.out.println("更新成功!");
        }else {
            System.out.println("沒有找到");
        }
    }

    //從雙向連結串列中刪除節點
    public void delete(String no){
        //直接找到對應no的節點直接刪除
        StudentNode cur = head.next;
        boolean flag = false; //標記是否找到
        while (true){
            if (cur == null){
                break;
            }
            if (cur.no.equals(no)){
                flag = true; //找到了
                break;
            }
            cur = cur.next;
        }
        if (flag){
            //刪除操作
            //注意考慮最後一個節點後一個為空的情況
            if (cur.next != null) {
                cur.next.pre = cur.pre;
            }
            cur.pre.next = cur.next;
            System.out.println("刪除成功!");
        }else {
            System.out.println( no + "節點不存在,無法刪除!");
        }
    }
}

2.3 測試類 StudentDoubleLinkedListDemo.java

/**
 * @author 興趣使然黃小黃
 * @version 1.0
 * 雙向連結串列測試類
 */
public class DoubleLinkedListDemo {
    public static void main(String[] args) {
        StudentDoubleLinkedList doubleLinkedList = new StudentDoubleLinkedList();
        doubleLinkedList.addByOrder(new StudentNode("1", "黃小黃", 20));
        doubleLinkedList.addByOrder(new StudentNode("3", "懶羊羊", 20));
        doubleLinkedList.addByOrder(new StudentNode("2", "沸羊羊", 25));
        doubleLinkedList.addByOrder(new StudentNode("4", "美羊羊", 15));
        System.out.println("遍歷:");
        doubleLinkedList.showList();

        //測試更新方法
        System.out.println("n更新編號為4的資訊後:");
        doubleLinkedList.update(new StudentNode("4", "禰豆子", 14));
        doubleLinkedList.showList();

        //測試刪除方法
        System.out.println("n刪除第一個和最後一個:");
        doubleLinkedList.delete("1");
        doubleLinkedList.delete("4");
        doubleLinkedList.showList();
    }
}

2.4 結果

遍歷:
StudentNode{no='1', name='黃小黃', age=20}--->StudentNode{no='2', name='沸羊羊', age=25}--->StudentNode{no='3', name='懶羊羊', age=20}--->StudentNode{no='4', name='美羊羊', age=15}
更新編號為4的資訊後:
更新成功!
StudentNode{no='1', name='黃小黃', age=20}--->StudentNode{no='2', name='沸羊羊', age=25}--->StudentNode{no='3', name='懶羊羊', age=20}--->StudentNode{no='4', name='禰豆子', age=14}
刪除第一個和最後一個:
刪除成功!
刪除成功!
StudentNode{no='2', name='沸羊羊', age=25}--->StudentNode{no='3', name='懶羊羊', age=20}
Process finished with exit code 0

3 雙向連結串列小結

單向連結串列查詢的方向只能為一個方向,雙向連結串列解決了這個缺點,可以實現雙向查詢;

單連結串列進行刪除操作必須找到待刪除元素的前一個元素,才能完成刪除操作。而雙向連結串列就簡單多了,只需要找到待刪除的節點,進行自我刪除;

本節介紹了雙向連結串列的遍歷、新增、按順序新增、更新、刪除方法的實現,可以嘗試像單連結串列篇一樣,嘗試求有效節點數量,以及如何逆序輸出雙向連結串列加強練習!

以上就是Java資料結構之雙向連結串列的實現的詳細內容,更多關於Java資料結構雙向連結串列的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com