1. 程式人生 > 實用技巧 >演算法學習第三日之雙向連結串列

演算法學習第三日之雙向連結串列

單向連結串列的缺點

雙向連結串列設計思路:

程式碼實現:
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 + "]";
	}

}