1. 程式人生 > 實用技巧 >資料結構(三)-單向連結串列

資料結構(三)-單向連結串列

連結串列介紹

連結串列是有序的列表,在記憶體中的結構如下圖所示

從上圖可以看出

  1. 連結串列以節點的方式儲存,是**鏈式儲存**,在記憶體中的地址不連續
  2. 每個節點都包含了data域和next域:指向下一個節點的記憶體地址。(帶head的連結串列其中head節點只包含next域,不儲存資料)
  3. 連結串列分為**帶頭節點連結串列**和**不帶頭節點連結串列**

單鏈錶帶頭結點的示意圖如下

單鏈表的應用例項(增刪改查)

HeroNode類

// 建立節點類
class HeroNode{
	
	public int no;
	public String name;
	public String nickName;
	public HeroNode next;
	// 用來建立頭節點
	public HeroNode(int no) {
		super();
		this.no = no;
	}
	// 用來建立資料節點
	public HeroNode(int no, String name, String nickName) {
		super();
		this.no = no;
		this.name = name;
		this.nickName = nickName;
	}
	@Override
	public String toString() {
		return "HeroNode [no=" + no + ", name=" + name + ", nickName=" + nickName + "]";
	}
}

新增(append)

思路分析
  1. 先遍歷連結串列,找到連結串列的最後
  2. 將最後一個節點的next域指向要新增的資料即可
程式碼實現
	// 1. 新增資料節點到連結串列最後
	public void add(HeroNode hero) {
		// 1.1 找到連結串列的末尾
		// 建立臨時指標
		HeroNode temp = head;
		while(true) {
			if(temp.next == null) {
				break;
			}
			temp = temp.next;
		}
		
		// 1.2 將資料新增到末尾
		temp.next = hero;
	}

新增(insert)

思路分析
  1. 遍歷連結串列
  2. 用待新增的節點的標識和已有連結串列的節點進行比對
        三種情況:
        1) 連結串列遍歷完發現沒找到能插入的位置,直接新增到末尾
        2) 發現可以插入的位置,將待插入節點插入
        3) 發現待與帶插入節點存在相同節點,不插入
  3. 新增的操作如上,插入的操作:hero.next = temp.next; temp.next = hero;
程式碼實現
	// 2. 按照英雄編號來新增資料
	public void addByOrder(HeroNode hero) {
		// 2.1 定義臨時指標
		HeroNode temp = head;
		// 2.2 定義標記追蹤是否可新增資料
		boolean flag = false; // false 表示可以新增
		
		while(true) {
			if(temp.next == null) { // 判斷連結串列是否遍歷完
				break;
			}
			if(temp.next.no > hero.no) { // 判斷是否找到可以插入的位置
				break;
			}else if(temp.next.no == hero.no) { // 判斷此位置上是否有資料
				flag = true;
				break;
			}
			temp = temp.next; // 遍歷連結串列
		}
		
		if(flag) {
			System.out.printf("%d 號位置上已有英雄,無法新增\n", hero.no);
		}else {
			hero.next = temp.next;
			temp.next = hero;
		}
	}

修改(update)

思路分析
  1. 遍歷連結串列,找到要修改的位置
  2. 新節點的屬性賦給舊節點
程式碼實現
	// 3. 根據no來修改節點上的資料
	public void update(HeroNode newHero) {
		// 判斷連結串列是否為空
		if(head.next == null) {
			System.out.println("連結串列為空");
		}
		// 定義臨時指標
		HeroNode temp = head.next;
		// 定義標記追蹤是否可以根據no找到對應的節點
		boolean flag = false; // false為沒找到
		while(true) {
			if(temp == null) { // 判斷連結串列是否遍歷完
				break;
			}
			if(temp.no == newHero.no) { // 判斷是否找到對應的節點
				flag = true;
				break;
			}
			temp = temp.next; // 後移
		}
		
		if(flag) {
			temp.name = newHero.name;
			temp.nickName = newHero.nickName;
		}else {
			System.out.printf("要修改的節點 %d 不存在,不能修改\n", newHero.no);
		}
		
	}

刪除(delete)

思路分析
  1. 遍歷連結串列,找到要刪除的位置
  2. 刪除對應節點:temp.next = temp.next.next; 將當前節點指向下一個節點的下一個節點(注意,刪除的是當前節點的下一個節點)
程式碼實現
	// 4. 根據no刪除對應的節點
	public void delete(int no) {
		// 定義臨時指標
		HeroNode temp = head;
		// 定義標記是否找到對應節點
		boolean flag = false;
		// 遍歷連結串列
		while(true) {
			if(temp.next == null) {// 判斷連結串列是否遍歷完
				break;
			}
			if(no == temp.next.no) { // 判斷是否找到對應節點
				flag = true;
				break;
			}
			temp = temp.next;
		}
		
		if(flag) {
			temp.next = temp.next.next;
		}else {
			System.out.printf("要刪除的節點 %d 不存在,不能刪除\n", no);
		}
		
	}

遍歷(list)

程式碼實現
	// 5. 遍歷連結串列
	public void list() {
		// 定義臨時指標
		HeroNode temp = head.next;
		if(temp == null) {
			System.out.println("連結串列為空");
			return;
		}
		while(true) {
			// 判斷連結串列是否遍歷完
			if(temp == null) {
				break;
			}
			// 輸出節點資訊並將臨時指標後移
			System.out.println(temp);
			temp = temp.next;
		}
	}

本篇隨筆內容是來自於學習尚矽谷韓順平老師的資料結構和演算法課(java版)的筆記,如有整理疏漏或錯誤之處,請大家多多指出