欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java數(shù)據(jù)結(jié)構(gòu)與算法之雙向鏈表、環(huán)形鏈表及約瑟夫問題深入理解

 更新時(shí)間:2021年09月13日 09:45:20   作者:威斯布魯克.猩猩  
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)與算法之雙向鏈表、環(huán)形鏈表及約瑟夫問題深入理解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

一、雙向鏈表

使用帶head頭的雙向鏈表實(shí)現(xiàn) - 水滸英雄排行榜管理單向鏈表的缺點(diǎn)分析:

  1. 單向鏈表,查找的方向只能是一個(gè)方向,而雙向鏈表可以向前或者向后查找。
  2. 單向鏈表不能自我刪除,需要靠輔助節(jié)點(diǎn),而雙向鏈表,則可以自我刪除,所以前面我們單鏈表刪除節(jié)點(diǎn)時(shí),總是找到temp,temp時(shí)待刪除節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)(認(rèn)真體會)。

分析雙向鏈表的遍歷,添加,修改,刪除的操作思路

1.遍歷和單鏈表一樣只是可以向前,也可以向后查找

2.添加(默認(rèn)添加到雙向鏈表的最后)

  • 先找到雙向鏈表的最后這個(gè)節(jié)點(diǎn)
  • temp.next = newHeroNode
  • newHeroNode.pre = temp

3.修改思路和原理與單向鏈表一樣

4.刪除

  • 因?yàn)闀r(shí)雙向鏈表,因此,我們可以實(shí)現(xiàn)自我刪除某個(gè)節(jié)點(diǎn)
  • 直接找到要?jiǎng)h除的這個(gè)節(jié)點(diǎn),比如temp
  • temp.pre.next = temp.next
  • temp.next.pre = temp.pre
public class DoubleLinkedListDemo {
	public static void main(String[] args) {
		// 測試
		System.out.println("雙向鏈表的測試");
		// 先創(chuàng)建節(jié)點(diǎn)
		HeroNode2 hero1 = new HeroNode2(1, "宋江", "及時(shí)雨");
		HeroNode2 hero2 = new HeroNode2(2, "盧俊義", "玉麒麟");
		HeroNode2 hero3 = new HeroNode2(3, "吳用", "智多星");
		HeroNode2 hero4 = new HeroNode2(4, "林沖", "豹子頭");
		// 創(chuàng)建一個(gè)雙向鏈表
		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();
	}
}
//創(chuàng)建一個(gè)雙向鏈表的類
class DoubleLinkedList {
	// 先初始化一個(gè)頭節(jié)點(diǎn),頭節(jié)點(diǎn)不要?jiǎng)?,不存放具體的數(shù)據(jù)
	private HeroNode2 head = new HeroNode2(0, "", "");
	// 返回頭節(jié)點(diǎn)
	public HeroNode2 getHead() {
		return head;
	}
	// 顯示鏈表[遍歷]
	public void list() {
		// 判斷鏈表是否為空
		if (head.next == null) {
			System.out.println("鏈表為空");
			return;
		}
		// 因?yàn)轭^節(jié)點(diǎn),不能動(dòng),因此我們需要一個(gè)輔助變量來遍歷
		HeroNode2 temp = head.next;
		while (true) {
			// 判斷是否到鏈表最后
			if (temp == null) {
				break;
			}
			// 輸出節(jié)點(diǎn)的信息
			System.out.println(temp);
			// 將temp后移,一定小心
			temp = temp.next;
		}
	}
	// 添加一個(gè)節(jié)點(diǎn)到雙向鏈表的最后
	public void add(HeroNode2 heroNode) {
		// 因?yàn)閔ead節(jié)點(diǎn)不能動(dòng),因此我們需要一個(gè)輔助變量temp
		HeroNode2 temp = head;
		// 遍歷鏈表,找到最后
		while (true) {
			// 找到鏈表的最后
			if (temp.next == null) {
				break;
			}
			// 如果沒有找到最后,將temp后移
			temp = temp.next;
		}
		// 當(dāng)退出while循環(huán)時(shí),temp就指向了鏈表的最后
		// 形成一個(gè)雙向鏈表
		temp.next = heroNode;
		heroNode.pre = temp;
	}
	// 修改一個(gè)節(jié)點(diǎn)的內(nèi)容,雙向鏈表的節(jié)點(diǎn)內(nèi)容修改和單向鏈表一樣
	// 只是節(jié)點(diǎn)類型改成HeroNode2
	public void update(HeroNode2 newHeroNode) {
		// 判斷是否空
		if (head.next == null) {
			System.out.println("鏈表為空~~");
			return;
		}
		// 找到需要修改的節(jié)點(diǎn),根據(jù)no編號
		// 定義一個(gè)輔助變量
		HeroNode2 temp = head.next;
		boolean flag = false;// 表示是否找到該節(jié)點(diǎn)
		while (true) {
			if (temp == null) {
				break;// 已經(jīng)遍歷完鏈表
			}
			if (temp.no == newHeroNode.no) {
				// 找到
				flag = true;
				break;
			}
			temp = temp.next;
		}
		// 根據(jù)flag判斷是否找到要修改的節(jié)點(diǎn)
		if (flag) {
			temp.name = newHeroNode.name;
			temp.nickname = newHeroNode.nickname;
		} else {// 沒有找到
			System.out.printf("沒有找到編號 %d 的節(jié)點(diǎn),不能修改\n", newHeroNode.no);
		}
	}
	// 從雙向鏈表中刪除一個(gè)節(jié)點(diǎn)
	// 說明
	// 1. 對于雙向鏈表,我們可以直接找到要?jiǎng)h除的這個(gè)節(jié)點(diǎn)
	// 2. 找到后,自我刪除即可
	public void del(int no) {
		// 判斷當(dāng)前鏈表是否為空
		if (head.next == null) {// 空鏈表
			System.out.println("鏈表為空,無法刪除");
			return;
		}
		HeroNode2 temp = head.next;// 輔助變量(指針),指向第一個(gè)節(jié)點(diǎn)(與單向鏈表不同)
		boolean flag = false;// 標(biāo)志是否找到待刪除節(jié)點(diǎn)
		while (true) {
			if (temp.next == null) {// 已經(jīng)到鏈表的最后節(jié)點(diǎn)的next
				break;
			}
			if (temp.next.no == no) {
				// 找到的待刪除節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)temp
				flag = true;
				break;
			}
			temp = temp.next;// temp后移,遍歷
		}
		// 判斷flag
		if (flag) {// 找到
			// 可以刪除
			temp.pre.next = temp.next;
			// 如果是最后一個(gè)節(jié)點(diǎn),就不需要執(zhí)行下面的這句話,否則出現(xiàn)空指針
			if (temp.next != null) {
				temp.next.pre = temp.pre;
			}
		} else {
			System.out.printf("要?jiǎng)h除的 %d 節(jié)點(diǎn)不存在\n", no);
		}
	}
}
//定義HeroNode2,每個(gè)HeroNode對象就是一個(gè)節(jié)點(diǎn)
class HeroNode2 {
	public int no;
	public String name;
	public String nickname;
	public HeroNode2 next;// 指向下一個(gè)節(jié)點(diǎn),默認(rèn)為null
	public HeroNode2 pre;// 指向前一個(gè)節(jié)點(diǎn),默認(rèn)為null
	// 構(gòu)造器
	public HeroNode2(int no, String name, String nickname) {
		this.no = no;
		this.name = name;
		this.nickname = nickname;
	}
	// 為了顯示方便,我們重寫toString
	@Override
	public String toString() {
		return "HeroNode2 [no=" + no + ", name=" + name + ", nickname=" + nickname + "]";
	}
}

二、環(huán)形鏈表及其應(yīng)用:約瑟夫問題

環(huán)形鏈表圖示

構(gòu)建一個(gè)單向的環(huán)形鏈表思路

1.先創(chuàng)建第一個(gè)節(jié)點(diǎn),讓 first 指向該節(jié)點(diǎn),并形成環(huán)形

2.后面當(dāng)我們每創(chuàng)建一個(gè)新的節(jié)點(diǎn),就把該節(jié)點(diǎn)加入到已有的環(huán)形鏈表中即可。

遍歷環(huán)形鏈表

1.先讓一個(gè)輔助指針(變量)curBoy,指向 first 節(jié)點(diǎn)

2.然后通過一個(gè) while 循環(huán)遍歷該環(huán)形鏈表即可 cur.Boy.next == first 結(jié)束

約瑟夫問題

1.創(chuàng)建一個(gè)輔助指針(變量)helper,事先應(yīng)該指向環(huán)形鏈表的最后這個(gè)節(jié)點(diǎn)。

2.小孩報(bào)數(shù)前,先讓 first 和 helper 移動(dòng) k -1次(移動(dòng)到報(bào)數(shù)的小孩

3.當(dāng)小孩報(bào)數(shù)時(shí),讓 first 和 helper 指針同時(shí)的移動(dòng) m - 1次

4.這時(shí)就可以將 first 指向的小孩節(jié)點(diǎn)出圈

first = first.next

helper.next = first

原來 first 指向的節(jié)點(diǎn)就沒有任何引用,就會被回收

public class Josepfu {
	public static void main(String[] args) {
		// 測試看看構(gòu)建環(huán)形鏈表,和遍歷是否ok
		CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
		circleSingleLinkedList.addBoy(5);// 加入5個(gè)小孩節(jié)點(diǎn)
		circleSingleLinkedList.showBoy();
		// 測試小孩出圈是否正確
		circleSingleLinkedList.countBoy(1, 2, 5);// 2->4->1->5->3
	}
}
//創(chuàng)建一個(gè)環(huán)形的單向鏈表
class CircleSingleLinkedList {
	// 創(chuàng)建一個(gè)first節(jié)點(diǎn),當(dāng)前沒有編號
	private Boy first = null;
 
	// 添加小孩節(jié)點(diǎn),構(gòu)建一個(gè)環(huán)形的鏈表
	public void addBoy(int nums) {
		// nums 做一個(gè)數(shù)據(jù)校驗(yàn)
		if (nums < 1) {
			System.out.println("nums的值不正確");
			return;
		}
		Boy curBoy = null;// 輔助指針,幫助構(gòu)建環(huán)形鏈表
		// 使用for來創(chuàng)建環(huán)形鏈表
		for (int i = 1; i <= nums; i++) {
			// 根據(jù)編號,創(chuàng)建小孩節(jié)點(diǎn)
			Boy boy = new Boy(i);
			// 如果是第一個(gè)小孩
			if (i == 1) {
				first = boy;
				first.setNext(first);// 構(gòu)成環(huán)(暫時(shí)是一個(gè)節(jié)點(diǎn)的環(huán))
				curBoy = first;// 讓curBoy指向第一個(gè)小孩
			} else {// 這塊的操作看不懂,可以回去看一下當(dāng)時(shí)老師視頻里的流程圖,特別好理解?。。。。。。。。。?
				curBoy.setNext(boy);
				boy.setNext(first);
				curBoy = boy;
			}
		}
	}
	// 遍歷當(dāng)前的環(huán)形鏈表
	public void showBoy() {
		// 判斷鏈表是否為空
		if (first == null) {
			System.out.println("沒有任何小孩~~");
			return;
		}
		// 因?yàn)閒irst不能動(dòng),因此我們?nèi)匀皇褂靡粋€(gè)輔助指針完成遍歷
		Boy curBoy = first;
		while (true) {
			System.out.printf("小孩的編號 %d \n", curBoy.getNo());
			if (curBoy.getNext() == first) {// 說明已經(jīng)遍歷完畢
				break;
			}
			curBoy = curBoy.getNext();// curBoy后移
		}
	}
	// 根據(jù)用戶的輸入,計(jì)算出小孩出圈的順序
	/**
	 * @param startNo  表示從第幾個(gè)小孩開始數(shù)數(shù)
	 * @param countNum 表示數(shù)幾下
	 * @param nums     表示最初有多少小孩在圈中
	 */
	public void countBoy(int startNo, int countNum, int nums) {
		// 先對數(shù)據(jù)進(jìn)行校驗(yàn)
		if (first == null || startNo < 1 || startNo > nums) {
			System.out.println("參數(shù)輸入有誤,請重新輸入");
			return;
		}
		// 創(chuàng)建一個(gè)輔助指針,幫助完成小孩出圈
		Boy helper = first;
		// 需要?jiǎng)?chuàng)建一個(gè)輔助指針(變量)helper,事先應(yīng)該指向環(huán)形鏈表的最后這個(gè)節(jié)點(diǎn)
		while (true) {
			if (helper.getNext() == first) {// 說明helper指向最后小孩節(jié)點(diǎn)
				break;
			}
			helper = helper.getNext();
		}
		// 小孩報(bào)數(shù)前,先讓first 和 helper 移動(dòng) k - 1次
		for (int j = 0; j < startNo - 1; j++) {
			first = first.getNext();
			helper = helper.getNext();
		}
		// 當(dāng)小孩報(bào)數(shù)時(shí),讓 first 和 helper 指針同時(shí)的移動(dòng) m -1次,然后出圈
		// 這里是一個(gè)循環(huán)操作,直到圈中只有一個(gè)節(jié)點(diǎn)
		while (true) {
			if (helper == first) {// 說明圈中只有一個(gè)節(jié)點(diǎn)
				break;
			}
			// 讓first 和 helper 指針同時(shí)的移動(dòng) countNum - 1
			for (int j = 0; j < countNum - 1; j++) {
				first = first.getNext();
				helper = helper.getNext();
			}
			// 這時(shí)first指向的節(jié)點(diǎn),就是要出圈的小孩節(jié)點(diǎn)
			System.out.printf("小孩%d出圈\n", first.getNo());
			// 這時(shí)將first指向的小孩節(jié)點(diǎn)出圈
			first = first.getNext();
			helper.setNext(first);
		}
		System.out.printf("最后留在圈中的小孩編號%d \n", first.getNo());
	}
}
//創(chuàng)建一個(gè)Boy類,表示一個(gè)節(jié)點(diǎn)
class Boy {
	private int no;// 編號
	private Boy next;// 指向下一個(gè)節(jié)點(diǎn),默認(rèn)null
 
	public Boy(int no) {
		this.no = no;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	public Boy getNext() {
		return next;
	}
	public void setNext(Boy next) {
		this.next = next;
	}
}

到此這篇關(guān)于Java數(shù)據(jù)結(jié)構(gòu)與算法之雙向鏈表、環(huán)形鏈表及約瑟夫問題深入理解的文章就介紹到這了,更多相關(guān)Java數(shù)據(jù)結(jié)構(gòu)與算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java8新特性之日期時(shí)間API

    java8新特性之日期時(shí)間API

    這篇文章主要介紹了java8新特性之日期時(shí)間API,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • jvm字符串常量池在什么內(nèi)存區(qū)域問題解析

    jvm字符串常量池在什么內(nèi)存區(qū)域問題解析

    這篇文章主要介紹了jvm字符串常量池在什么內(nèi)存區(qū)域的問題解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Java之經(jīng)典排序算法

    Java之經(jīng)典排序算法

    這篇文章主要介紹了Java的一些經(jīng)典排序算法,對Java算法感興趣的小伙伴可以詳細(xì)參考閱讀本文,對同學(xué)們有一定的參考價(jià)值
    2023-03-03
  • 圖文詳解SpringBoot中Log日志的集成

    圖文詳解SpringBoot中Log日志的集成

    這篇文章主要給大家介紹了關(guān)于SpringBoot中Log日志的集成的相關(guān)資料,文中通過實(shí)例代碼以及圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2021-12-12
  • SpringCloud學(xué)習(xí)筆記之SpringCloud搭建父工程的過程圖解

    SpringCloud學(xué)習(xí)筆記之SpringCloud搭建父工程的過程圖解

    SpringCloud是分布式微服務(wù)架構(gòu)的一站式解決方案,十多種微服務(wù)架構(gòu)落地技術(shù)的集合體,俗稱微服務(wù)全家桶,這篇文章主要介紹了SpringCloud學(xué)習(xí)筆記(一)搭建父工程,需要的朋友可以參考下
    2021-10-10
  • java基礎(chǔ)之Object類

    java基礎(chǔ)之Object類

    這篇文章主要介紹了java基礎(chǔ)之Object類 的相關(guān)資料,需要的朋友可以參考下
    2015-06-06
  • Spring整合mybatis實(shí)現(xiàn)過程詳解

    Spring整合mybatis實(shí)現(xiàn)過程詳解

    這篇文章主要介紹了Spring整合mybatis實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • 深入淺析java中finally的用法

    深入淺析java中finally的用法

    finally自己由關(guān)鍵字finally和后面的finally塊組成。這篇文章重點(diǎn)給大家介紹java中finally的用法,需要的朋友參考下吧
    2018-06-06
  • postman中POST請求時(shí)參數(shù)包含參數(shù)list設(shè)置方式

    postman中POST請求時(shí)參數(shù)包含參數(shù)list設(shè)置方式

    這篇文章主要介紹了postman中POST請求時(shí)參數(shù)包含參數(shù)list設(shè)置方式,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • java程序員自己的圖片轉(zhuǎn)文字OCR識圖工具分享

    java程序員自己的圖片轉(zhuǎn)文字OCR識圖工具分享

    這篇文章主要介紹了java程序員自己的圖片轉(zhuǎn)文字OCR識圖工具,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11

最新評論