最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

 更新時(shí)間:2021年09月13日 09:45:20   作者:威斯布魯克.猩猩  
這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)與算法之雙向鏈表、環(huán)形鏈表及約瑟夫問題深入理解,本文給大家介紹的非常詳細(xì),對(duì)大家的學(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)真體會(huì))。

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

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) {
		// 測(cè)試
		System.out.println("雙向鏈表的測(cè)試");
		// 先創(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編號(hào)
		// 定義一個(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("沒有找到編號(hào) %d 的節(jié)點(diǎn),不能修改\n", newHeroNode.no);
		}
	}
	// 從雙向鏈表中刪除一個(gè)節(jié)點(diǎn)
	// 說明
	// 1. 對(duì)于雙向鏈表,我們可以直接找到要?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對(duì)象就是一個(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)就沒有任何引用,就會(huì)被回收

public class Josepfu {
	public static void main(String[] args) {
		// 測(cè)試看看構(gòu)建環(huán)形鏈表,和遍歷是否ok
		CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
		circleSingleLinkedList.addBoy(5);// 加入5個(gè)小孩節(jié)點(diǎn)
		circleSingleLinkedList.showBoy();
		// 測(cè)試小孩出圈是否正確
		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)前沒有編號(hào)
	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ù)編號(hào),創(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("小孩的編號(hào) %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) {
		// 先對(duì)數(shù)據(jù)進(jìn)行校驗(yàn)
		if (first == null || startNo < 1 || startNo > nums) {
			System.out.println("參數(shù)輸入有誤,請(qǐng)重新輸入");
			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("最后留在圈中的小孩編號(hào)%d \n", first.getNo());
	}
}
//創(chuàng)建一個(gè)Boy類,表示一個(gè)節(jié)點(diǎn)
class Boy {
	private int no;// 編號(hào)
	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)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Log4j日志分類和過濾敏感字段的實(shí)例

    Log4j日志分類和過濾敏感字段的實(shí)例

    這篇文章主要介紹了Log4j日志分類和過濾敏感字段的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • java 中clone()的使用方法

    java 中clone()的使用方法

    這篇文章主要介紹了java 中clone()的使用方法的相關(guān)資料,希望通過本文能幫助大家能掌握clone()的克隆方法,需要的朋友可以參考下
    2017-09-09
  • java實(shí)現(xiàn)微信公眾號(hào)掃一掃

    java實(shí)現(xiàn)微信公眾號(hào)掃一掃

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)微信公眾號(hào)掃一掃,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-04-04
  • Spring Boot 中的 @Field 注解的原理解析

    Spring Boot 中的 @Field 注解的原理解析

    本文詳細(xì)介紹了 Spring Boot 中的 @Field 注解的原理和使用方法,通過使用 @Field 注解,我們可以將 HTTP 請(qǐng)求中的參數(shù)值自動(dòng)綁定到 Java 對(duì)象的屬性上,簡化了開發(fā)過程,提高了開發(fā)效率,感興趣的朋友跟隨小編一起看看吧
    2023-07-07
  • IDEA搭建多模塊的Maven項(xiàng)目方式(相互依賴)

    IDEA搭建多模塊的Maven項(xiàng)目方式(相互依賴)

    這篇文章主要介紹了IDEA搭建多模塊的Maven項(xiàng)目方式(相互依賴),具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 解析SpringBoot?搭建基于?MinIO?的高性能存儲(chǔ)服務(wù)的問題

    解析SpringBoot?搭建基于?MinIO?的高性能存儲(chǔ)服務(wù)的問題

    Minio是Apache?License?v2.0下發(fā)布的對(duì)象存儲(chǔ)服務(wù)器,使用MinIO構(gòu)建用于機(jī)器學(xué)習(xí),分析和應(yīng)用程序數(shù)據(jù)工作負(fù)載的高性能基礎(chǔ)架構(gòu)。這篇文章主要介紹了SpringBoot?搭建基于?MinIO?的高性能存儲(chǔ)服務(wù),需要的朋友可以參考下
    2022-03-03
  • SpringBoot讀取配置優(yōu)先級(jí)順序的方法詳解

    SpringBoot讀取配置優(yōu)先級(jí)順序的方法詳解

    Spring Boot作為一種輕量級(jí)的Java應(yīng)用程序框架,以其開箱即用、快速搭建新項(xiàng)目的特性贏得了廣大開發(fā)者的青睞,在Spring Boot生態(tài)系統(tǒng)中,配置屬性可以從各種來源獲取,本文將深入探討Spring Boot加載外部配置屬性的優(yōu)先級(jí)規(guī)則,需要的朋友可以參考下
    2024-05-05
  • Java實(shí)現(xiàn)整數(shù)的逆序輸出的三種方法

    Java實(shí)現(xiàn)整數(shù)的逆序輸出的三種方法

    這篇文章主要介紹了Java實(shí)現(xiàn)整數(shù)的逆序輸出的三種方法,第一種是無限制整數(shù)的逆序輸出,第二種是非負(fù)整數(shù)的逆序輸出,第三種是非特殊情況的逆序輸出,每種方法給大家講解的非常詳細(xì)需要的朋友可以參考下
    2022-11-11
  • 多線程-lock與lockInterruptibly的區(qū)別及說明

    多線程-lock與lockInterruptibly的區(qū)別及說明

    文章主要討論了Java中ReentrantLock的lock和lockInterruptibly方法的區(qū)別,以及AQS中的雙向鏈表設(shè)計(jì),lock方法不響應(yīng)中斷,而lockInterruptibly方法會(huì)響應(yīng)中斷,AQS的雙向鏈表設(shè)計(jì)使得線程管理更加高效和靈活,適用于高并發(fā)場(chǎng)景
    2025-02-02
  • 教你如何使用JAVA POI

    教你如何使用JAVA POI

    今天教大家怎么學(xué)習(xí)JAVA POI的用法,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05

最新評(píng)論

台北市| 贺州市| 文昌市| 新巴尔虎右旗| 汉沽区| 满洲里市| 平阳县| 保德县| 徐闻县| 崇阳县| 贵州省| 卓资县| 陇川县| 红安县| 泗阳县| 五家渠市| 泌阳县| 万山特区| 宝应县| 乾安县| 吉林省| 九龙城区| 黎平县| 稷山县| 都兰县| 辛集市| 理塘县| 凤冈县| 鹤峰县| 淮北市| 远安县| 南澳县| 通州区| 大城县| 黑河市| 鹿泉市| 汉寿县| 沐川县| 历史| 海宁市| 瑞丽市|