演算法學習第三日之雙向連結串列
阿新 • • 發佈:2021-01-07
單向連結串列的缺點
雙向連結串列設計思路:
程式碼實現:
package com.atguigu.linkedlist; public class DoubleLinkedListDemo { public static void main(String[] args) { // 測試 System.out.println("雙向連結串列的測試"); // 先建立節點 HeroNode2 hero1 = new HeroNode2(1, "宋江", "及時雨"); HeroNode2 hero2 = new HeroNode2(2, "盧俊義", "玉麒麟"); HeroNode2 hero3 = new HeroNode2(3, "吳用", "智多星"); HeroNode2 hero4 = new HeroNode2(4, "林沖", "豹子頭"); // 建立一個雙向連結串列 DoubleLinkedList doubleLinkedList = new DoubleLinkedList(); doubleLinkedList.add(hero1); doubleLinkedList.add(hero2); doubleLinkedList.add(hero3); doubleLinkedList.add(hero4); doubleLinkedList.list(); // 修改 HeroNode2 newHeroNode = new HeroNode2(4, "公孫勝", "入雲龍"); doubleLinkedList.update(newHeroNode); System.out.println("修改後的連結串列情況"); doubleLinkedList.list(); // 刪除 doubleLinkedList.del(3); System.out.println("刪除後的連結串列情況~~"); doubleLinkedList.list(); } } // 建立一個雙向連結串列的類 class DoubleLinkedList { // 先初始化一個頭節點, 頭節點不要動, 不存放具體的資料 private HeroNode2 head = new HeroNode2(0, "", ""); // 返回頭節點 public HeroNode2 getHead() { return head; } // 遍歷雙向連結串列的方法 // 顯示連結串列[遍歷] public void list() { // 判斷連結串列是否為空 if (head.next == null) { System.out.println("連結串列為空"); return; } // 因為頭節點,不能動,因此我們需要一個輔助變數來遍歷 HeroNode2 temp = head.next; while (true) { // 判斷是否到連結串列最後 if (temp == null) { break; } // 輸出節點的資訊 System.out.println(temp); // 將temp後移, 一定小心 temp = temp.next; } } // 新增一個節點到雙向連結串列的最後. public void add(HeroNode2 heroNode) { // 因為head節點不能動,因此我們需要一個輔助遍歷 temp HeroNode2 temp = head; // 遍歷連結串列,找到最後 while (true) { // 找到連結串列的最後 if (temp.next == null) {// break; } // 如果沒有找到最後, 將將temp後移 temp = temp.next; } // 當退出while迴圈時,temp就指向了連結串列的最後 // 形成一個雙向連結串列 temp.next = heroNode; heroNode.pre = temp; } // 修改一個節點的內容, 可以看到雙向連結串列的節點內容修改和單向連結串列一樣 // 只是 節點型別改成 HeroNode2 public void update(HeroNode2 newHeroNode) { // 判斷是否空 if (head.next == null) { System.out.println("連結串列為空~"); return; } // 找到需要修改的節點, 根據no編號 // 定義一個輔助變數 HeroNode2 temp = head.next; boolean flag = false; // 表示是否找到該節點 while (true) { if (temp == null) { break; // 已經遍歷完連結串列 } if (temp.no == newHeroNode.no) { // 找到 flag = true; break; } temp = temp.next; } // 根據flag 判斷是否找到要修改的節點 if (flag) { temp.name = newHeroNode.name; temp.nickname = newHeroNode.nickname; } else { // 沒有找到 System.out.printf("沒有找到 編號 %d 的節點,不能修改\n", newHeroNode.no); } } // 從雙向連結串列中刪除一個節點, // 說明 // 1 對於雙向連結串列,我們可以直接找到要刪除的這個節點 // 2 找到後,自我刪除即可 public void del(int no) { // 判斷當前連結串列是否為空 if (head.next == null) {// 空連結串列 System.out.println("連結串列為空,無法刪除"); return; } HeroNode2 temp = head.next; // 輔助變數(指標) boolean flag = false; // 標誌是否找到待刪除節點的 while (true) { if (temp == null) { // 已經到連結串列的最後 break; } if (temp.no == no) { // 找到的待刪除節點的前一個節點temp flag = true; break; } temp = temp.next; // temp後移,遍歷 } // 判斷flag if (flag) { // 找到 // 可以刪除 // temp.next = temp.next.next;[單向連結串列] temp.pre.next = temp.next; // 這裡我們的程式碼有問題? // 如果是最後一個節點,就不需要執行下面這句話,否則出現空指標 if (temp.next != null) { temp.next.pre = temp.pre; } } else { System.out.printf("要刪除的 %d 節點不存在\n", no); } } } // 定義HeroNode2 , 每個HeroNode 物件就是一個節點 class HeroNode2 { public int no; public String name; public String nickname; public HeroNode2 next; // 指向下一個節點, 預設為null public HeroNode2 pre; // 指向前一個節點, 預設為null // 構造器 public HeroNode2(int no, String name, String nickname) { this.no = no; this.name = name; this.nickname = nickname; } // 為了顯示方法,我們重新toString @Override public String toString() { return "HeroNode [no=" + no + ", name=" + name + ", nickname=" + nickname + "]"; } }