日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 综合教程 >内容正文

综合教程

图解Java数据结构之环形链表

發(fā)布時(shí)間:2024/1/3 综合教程 32 生活家
生活随笔 收集整理的這篇文章主要介紹了 图解Java数据结构之环形链表 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

本篇文章介紹數(shù)據(jù)結(jié)構(gòu)中的環(huán)形鏈表。

介紹

環(huán)形鏈表,類似于單鏈表,也是一種鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu),環(huán)形鏈表由單鏈表演化過(guò)來(lái)。單鏈表的最后一個(gè)結(jié)點(diǎn)的鏈域指向NULL,而環(huán)形鏈表的建立,不要專門(mén)的頭結(jié)點(diǎn),讓最后一個(gè)結(jié)點(diǎn)的鏈域指向鏈表結(jié)點(diǎn)。 簡(jiǎn)單點(diǎn)說(shuō)鏈表首位相連,組成環(huán)狀數(shù)據(jù)結(jié)構(gòu)。如下圖結(jié)構(gòu):

而在環(huán)形鏈表中,最為著名的即是約瑟夫環(huán)問(wèn)題。

約瑟夫環(huán)問(wèn)題

問(wèn)題介紹:
設(shè)編號(hào)為1、2、3、... 、n的n個(gè)人圍坐一圈,約定編號(hào)為k(1<=k<=n)的人從1開(kāi)始報(bào)數(shù),數(shù)到m的那個(gè)人出列,它的下一位又從1開(kāi)始報(bào)數(shù),數(shù)到m的那個(gè)人又出列。依次類推,直到所有人出列為止,由此產(chǎn)生一個(gè)出隊(duì)編號(hào)的序列。
我們可以舉個(gè)例子來(lái)分析一下:
假設(shè)一共有5個(gè)人,即n = 5;從第一個(gè)人開(kāi)始報(bào)數(shù),即k = 1;數(shù)到2的人出列,即m = 2。
示意圖如下:

出隊(duì)列的順序即為:2 -> 4 -> 1 -> 5 -> 3

那么我們首先得構(gòu)建出一個(gè)單向的環(huán)形鏈表。

實(shí)現(xiàn)分析:

先創(chuàng)建第一個(gè)節(jié)點(diǎn),讓first指向該節(jié)點(diǎn),并形成環(huán)狀
每創(chuàng)建一個(gè)新的節(jié)點(diǎn)就將該節(jié)點(diǎn)加入到已有的環(huán)形鏈表中

分析完畢,我們用代碼實(shí)現(xiàn)一下:

//創(chuàng)建一個(gè)環(huán)形的單向鏈表
class CircleSingleLinkedList {
	// 創(chuàng)建一個(gè)first節(jié)點(diǎn),當(dāng)前沒(méi)有編號(hào)
	private Boy first = null;

	// 添加節(jié)點(diǎn),構(gòu)建成一個(gè)環(huán)形鏈表
	public void addBoy(int nums) {
		// 對(duì)nums做一個(gè)校驗(yàn)
		if (nums < 1) {
			System.out.println("數(shù)據(jù)錯(cuò)誤");
			return;
		}

		// 定義輔助節(jié)點(diǎn)
		Boy curBoy = null;

		// 使用循環(huán)創(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è)節(jié)點(diǎn)
			if (i == 1) {
				first = boy;
				first.setNext(first);
				curBoy = first;// 讓curBoy指向第一個(gè)節(jié)點(diǎn),幫助構(gòu)建鏈表
			} else {
				curBoy.setNext(boy);
				boy.setNext(first);// 使其指向第一個(gè)節(jié)點(diǎn),形成環(huán)狀
				curBoy = boy;// curBoy后移
			}
		}
	}

	// 遍歷當(dāng)前環(huán)形鏈表
	public void list() {
		// 判斷鏈表是否空
		if (first == null) {
			System.out.println("鏈表為空");
			return;
		}
		// 定義輔助節(jié)點(diǎn)
		Boy curBoy = first;
		while (true) {
			System.out.println("節(jié)點(diǎn)編號(hào):" + curBoy.getNo());
			if (curBoy.getNext() == first) {
				// 此時(shí)說(shuō)明遍歷完畢
				break;
			}
			curBoy = curBoy.getNext();// curBoy后移
		}
	}
}

//創(chuàng)建一個(gè)Boy類,表示一個(gè)節(jié)點(diǎn)
class Boy {
	private int no;// 編號(hào)
	private Boy next;// 指向下一個(gè)節(jié)點(diǎn)

	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;
	}
}

這樣就實(shí)現(xiàn)了一個(gè)環(huán)形鏈表,接下來(lái)測(cè)試一下:

public static void main(String[] args) {
		CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
		circleSingleLinkedList.addBoy(5);
		circleSingleLinkedList.list();
}

運(yùn)行結(jié)果:

節(jié)點(diǎn)編號(hào):1
節(jié)點(diǎn)編號(hào):2
節(jié)點(diǎn)編號(hào):3
節(jié)點(diǎn)編號(hào):4
節(jié)點(diǎn)編號(hào):5

運(yùn)行結(jié)果也是沒(méi)有問(wèn)題的,接下來(lái)便是生成出圈序列。
問(wèn)題分析:

先創(chuàng)建一個(gè)輔助節(jié)點(diǎn)helper,事先應(yīng)該指向環(huán)形鏈表的最后一個(gè)節(jié)點(diǎn)
報(bào)數(shù)前,先讓first和helper移動(dòng)k - 1次
開(kāi)始報(bào)數(shù)時(shí),讓first和helper節(jié)點(diǎn)同時(shí)移動(dòng),移動(dòng)m - 1次
此時(shí)可以將first指向的節(jié)點(diǎn)出圈
如何出圈呢?
使first = first.next,即:將first節(jié)點(diǎn)往前移動(dòng)一下
使helper.next = first,這樣就跳過(guò)了要出圈的節(jié)點(diǎn)

接下來(lái)是代碼實(shí)現(xiàn):

	/**
	 * 根據(jù)用戶的輸入,計(jì)算出圈序列
	 * 
	 * @param startNo  表示從第幾個(gè)開(kāi)始數(shù)
	 * @param countNum 表示數(shù)幾下
	 * @param nums     表示一共有多少人
	 */
	public void countBoy(int startNo, int countNum, int nums) {
		// 數(shù)據(jù)校驗(yàn)
		if (first == null || startNo < 1 || startNo > nums) {
			System.out.println("參數(shù)輸入有誤");
			return;
		}
		// 定義輔助節(jié)點(diǎn)
		Boy helper = first;
		// helper事先應(yīng)該指向環(huán)形鏈表的最后一個(gè)節(jié)點(diǎn)
		while (true) {
			if (helper.getNext() == first) {
				break;
			}
			helper = helper.getNext();// helper后移
		}
		// 報(bào)數(shù)前,先讓first和helper移動(dòng)k - 1次
		for (int j = 0; j < startNo - 1; j++) {
			first = first.getNext();
			helper = helper.getNext();
		}
		// 開(kāi)始報(bào)數(shù)時(shí),讓first和helper節(jié)點(diǎn)同時(shí)移動(dòng),移動(dòng)m - 1次
		// 這里是一個(gè)循環(huán)的操作,直到圈中只有一個(gè)節(jié)點(diǎn)
		while (true) {
			if (helper == first) {
				// 此時(shí)說(shuō)明圈中只有一個(gè)人
				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.println("節(jié)點(diǎn)" + first.getNo() + "出圈");
			// 將該節(jié)點(diǎn)出圈
			first = first.getNext();
			helper.setNext(first);
		}
		System.out.println("最后留在圈中的節(jié)點(diǎn)編號(hào):" + first.getNo());
	}

這個(gè)實(shí)現(xiàn)的邏輯相對(duì)來(lái)說(shuō)還是比較復(fù)雜和難以理解的,接下來(lái)編寫(xiě)測(cè)試代碼:

	public static void main(String[] args) {
		CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
		circleSingleLinkedList.addBoy(5);
		circleSingleLinkedList.list();

		System.out.println("--------------");

		// 測(cè)試出圈序列
		circleSingleLinkedList.countBoy(1, 2, 5);
	}

運(yùn)行結(jié)果:

節(jié)點(diǎn)編號(hào):1
節(jié)點(diǎn)編號(hào):2
節(jié)點(diǎn)編號(hào):3
節(jié)點(diǎn)編號(hào):4
節(jié)點(diǎn)編號(hào):5
--------------
節(jié)點(diǎn)2出圈
節(jié)點(diǎn)4出圈
節(jié)點(diǎn)1出圈
節(jié)點(diǎn)5出圈
最后留在圈中的節(jié)點(diǎn)編號(hào):3

和開(kāi)始計(jì)算的結(jié)果相吻合。
到此,關(guān)于約瑟夫環(huán)的問(wèn)題就成功解決了。

總結(jié)

以上是生活随笔為你收集整理的图解Java数据结构之环形链表的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。