java資料結構與演算法三: 連結串列(雙向連結串列)
阿新 • • 發佈:2020-08-11
連結串列:雙鏈表
一、 雙向連結串列的操作分析和實現
(使用帶head頭的雙向連結串列實現 —— 水滸英雄排行榜)
1、管理單項鍊表的缺點分析:
- 單項鍊表,查詢的方向只能是一個方向,而雙向連結串列可以向前或者向後查詢
- 單項鍊表不能自我刪除,需要靠輔助節點,而雙向連結串列,可以自我刪除,所以單鏈表刪除節點時,總是找到temp,temp是待刪除節點的前一個節點
2、雙向連結串列完成遍歷、新增、修改和刪除的思路:
- 遍歷:和單鏈表一樣,只是可以向前,也可以向後查詢
- 新增:(預設新增到雙向連結串列的最後)
- 先找到雙向連結串列的最後這個節點
temp.next = newHeroNode
newHeroNode.pre = temp
- 修改與單鏈表一樣
- 刪除
- 因為是雙向連結串列,因此可以實現自我刪除某個節點
- 直接找到要刪除的這個節點,比如temp
temp.pre.next = temp.next
temp.next.pre = temp.pre
二、程式碼實現
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.addByOrder(hero1); doubleLinkedList.addByOrder(hero4); doubleLinkedList.addByOrder(hero3); doubleLinkedList.addByOrder(hero2); doubleLinkedList.list(); //修改 HeroNode2 hero5 = new HeroNode2(4,"公孫離","射手"); doubleLinkedList.update(hero5); 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; } //第二種新增方式:按照編號新增到指定位置 public void addByOrder(HeroNode2 newHeroNode) { HeroNode2 temp = head; boolean flag = false; while(true) { if(temp.next == null) { break; } //判斷位置 if(temp.next.no > newHeroNode.no) { break; }else if(temp.next.no == newHeroNode.no) { //編號重複 flag = true; break; } temp = temp.next; } if(flag) { System.out.printf("準備插入的英雄的編號%d已經存在,不能加入\n",newHeroNode.no); }else { if(temp.next == null) { temp.next = newHeroNode; newHeroNode.pre = temp; }else { temp.next.pre = newHeroNode; newHeroNode.next = temp.next; temp.next = newHeroNode; newHeroNode.pre = temp; } } } //修改一個節點的內容,雙向連結串列的節點內容修改和單向連結串列一樣 //只是節點的型別改成HeroNode2 public void update(HeroNode2 newHeroNode) { //判斷是否為空 if(head.next == null) { System.out.println("連結串列為空"); } //找到需要修改的節點,根據 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、找到後,自我刪除即可 * @param no */ public void del(int no) { //判斷當前連結串列是否為空 if (head.next == null) { System.out.println("連結串列為空,無法刪除"); return; } HeroNode2 temp = head.next; boolean flag = false; // 標誌是否找到待刪除的節點 while(true) { if(temp.next == null) { //已經到連結串列的最後 break; } if(temp.no == no) { //找到待刪除的節點temp flag = true; break; } temp = temp.next; } //判斷flag if(flag) { //找到,可以刪除 temp.pre.next = temp.next; //如果是最後一個節點,就不需要執行下面這句話,否則出現空指標 if (temp.next != null) { temp.next.pre = temp.pre; } }else { System.out.printf("要刪除的%d節點不存在\n",no); } } } //定義一個HeroNode,每個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 + "]"; } }