Java數(shù)據(jù)結(jié)構(gòu)之環(huán)形鏈表和約瑟夫問題詳解
一、環(huán)形鏈表
1、創(chuàng)建結(jié)點(diǎn)
環(huán)形鏈表其實(shí)也很好理解,就是將單鏈表的頭和尾連接起來,就形成了環(huán)形鏈表。
public class Node { public int data; public Node next; public Node(int data) { this.data = data; } @Override public String toString() { return "Node{" + "data=" + data + '}'; } }
2、添加小結(jié)點(diǎn)
寫一個(gè)方法用來添加結(jié)點(diǎn),這個(gè)方法我們直接傳入需要?jiǎng)?chuàng)建結(jié)點(diǎn)的個(gè)數(shù),然后再方法中直接創(chuàng)建出一個(gè)簡(jiǎn)單的循環(huán)鏈表。代碼解析:
//創(chuàng)建一個(gè)first結(jié)點(diǎn),當(dāng)前沒有編號(hào) public Node first = new Node(-1);
public void add(int n){ //其實(shí)循環(huán)鏈表,一個(gè)結(jié)點(diǎn)也可以循環(huán),但這里為了方便后面介紹約瑟夫問題 //我們循環(huán)的結(jié)點(diǎn)不能少于兩個(gè)所以做了這個(gè)判斷。 if (n < 2){ System.out.println("n的值不正確"); return; } //輔助結(jié)點(diǎn) Node end = null; //使用for循環(huán)來創(chuàng)建鏈表 for (int i = 1; i <= n; i++) { //根據(jù)編號(hào)創(chuàng)建結(jié)點(diǎn) Node node = new Node(i); //如果是第一個(gè)結(jié)點(diǎn),first頭指向第一個(gè)結(jié)點(diǎn),end表示尾,回過頭來指向first,形成循環(huán) if(i == 1){ first = node; end = first; }else{ //先將尾部end的next指向新的結(jié)點(diǎn)node,然后end后移指向新的結(jié)點(diǎn), //再將end的next指向第一個(gè)結(jié)點(diǎn)first,這樣就形成了循環(huán) end.next = node; end = end.next; end.next = first; } } }
3、顯示循環(huán)鏈表
顯示循環(huán)鏈表的方式和單鏈表的顯示方式差不多,關(guān)鍵點(diǎn)在于如何判斷循環(huán)鏈表的結(jié)束,我們的尾部是指向頭部的,所以當(dāng)尾部的next指向的結(jié)點(diǎn)等于頭部,就是最后一個(gè)結(jié)點(diǎn),此時(shí)就退出循環(huán)。
public void show(Node first){ //判斷循環(huán)鏈表是否為空 if (first.next == first){ System.out.println("列表為空!"); return; } //輔助結(jié)點(diǎn) Node temp = first; //循環(huán)打印 while (true){ System.out.println(temp); //最后一個(gè)結(jié)點(diǎn)的next等于first,就退出 if (temp.next == first){ break; } temp = temp.next; } }
二、約瑟夫問題
1、問題描述
約瑟夫(Joseph)問題的一種描述是:編號(hào)為1,2,...n的n個(gè)人按順時(shí)針方向圍坐一圈,每人持有一個(gè)密碼(正整數(shù))。開始選任一個(gè)正整數(shù)作為報(bào)數(shù)上限值m, 從第一個(gè)人開始按順時(shí)針方向自1開始順序報(bào)數(shù), 報(bào)到m時(shí)停止報(bào)數(shù)。 報(bào)m的人出列, 將它的密碼作為新的m值。 試設(shè)計(jì)一個(gè)程序求出出列順序。
2、首先確定圈大小及開始位置
? 寫一個(gè)方法
start :表示從哪一個(gè)位置開始
m : 報(bào)多少個(gè)數(shù),報(bào)到m個(gè)數(shù)的人出列
n :圈總的大小
public void goOutCircle(int start,int m, int n){ }
? 確定圈的大小
傳入的n要多余兩個(gè)人才能玩,然后傳入的開始位置start不能在總?cè)藬?shù)之外,符合條件,我們調(diào)用前面我們介紹的方法add()進(jìn)行循環(huán)鏈表的創(chuàng)建。
if (n >= 2 && start <= n){ add(n); }else { System.out.println("輸入異常!"); return; }
? 確定開始位置
first是指向鏈表的第一個(gè)的,但我們開始的位置可以是任何一個(gè)結(jié)點(diǎn),所以先聲明輔助結(jié)點(diǎn)temp,遍歷循環(huán)鏈表,如果結(jié)點(diǎn)的data和傳入的start的值相等,就找到了開始位置,將first 指向開始位置temp,然后循環(huán)就結(jié)束了。
Node temp = first; while (true){ if (temp.data == start){ first = temp; break; } temp = temp.next; }
3、出圈操作
首先,我們需要一個(gè)輔助的結(jié)點(diǎn)end,然后假設(shè)開始位置在數(shù)據(jù)2的地方,first和end都指向數(shù)據(jù)2,數(shù)的次數(shù)為m = 2。
開始數(shù)數(shù),數(shù)據(jù)3的位置是數(shù)數(shù)m = 2 的時(shí)候,這時(shí)數(shù)據(jù)3應(yīng)該出圈。
first繼續(xù)指向要出圈數(shù)據(jù)的下一個(gè)結(jié)點(diǎn),end所在的結(jié)點(diǎn)指向first指向的結(jié)點(diǎn),就讓數(shù)據(jù)3出圈了。
結(jié)點(diǎn)出圈后,first和end又同時(shí)指向一個(gè)結(jié)點(diǎn),m 又開始重新計(jì)數(shù) ,如此循環(huán)下去即可。
Node end = first; while (true) { //當(dāng)總數(shù)只有一個(gè)的時(shí)候,循環(huán)結(jié)束。 if (n == 1) { System.out.println("勝利者為" + first + "號(hào)"); break; } //用for循環(huán),循環(huán)次數(shù)為 m - 1,因?yàn)楸旧硪獢?shù)一個(gè)數(shù) for (int i = 1; i <= m - 1; i++) { //first指向下一個(gè)結(jié)點(diǎn) first = first.next; //如果找到了要出圈的結(jié)點(diǎn),first是正好指向它的 if (i == m - 1) { //first指向的這個(gè)結(jié)點(diǎn)出圈 System.out.println(first + "號(hào)出圈"); //每出圈一個(gè),總數(shù)減一 n--; //first繼續(xù)指向下一個(gè)結(jié)點(diǎn) first = first.next; //此時(shí)end還在出圈結(jié)點(diǎn)的前一個(gè)位置,end的next指向first end.next = first; //end也同樣指向first指向的結(jié)點(diǎn) end = first; break; } //如果沒有到要出圈的結(jié)點(diǎn),end繼續(xù)跟著first指向同一個(gè)結(jié)點(diǎn) end = first; } }
4、出圈方法完整代碼
public void goOutCircle(int start,int m, int n){ //首先確定圈的大小 if (n >= 2 && start <= n){ add(n); }else { System.out.println("輸入異常!"); return; } //確定數(shù)數(shù)的位置 Node temp = first; while (true){ if (temp.data == start){ first = temp; break; } temp = temp.next; } //進(jìn)行遍歷 Node end = first; while (true) { if (n == 1) { System.out.println("勝利者為" + first + "號(hào)"); break; } for (int i = 1; i <= m - 1; i++) { first = first.next; if (i == m - 1) { System.out.println(first + "號(hào)出圈"); n--; first = first.next; end.next = first; end = first; break; } end = first; } } }
運(yùn)行結(jié)果:
總結(jié)
到此這篇關(guān)于Java數(shù)據(jù)結(jié)構(gòu)之環(huán)形鏈表和約瑟夫問題詳解的文章就介紹到這了,更多相關(guān)Java環(huán)形鏈表和約瑟夫問題內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java算法題解??虰M99順時(shí)針旋轉(zhuǎn)矩陣示例
這篇文章主要為大家介紹了java算法題解??虰M99順時(shí)針旋轉(zhuǎn)矩陣示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01Java中遍歷集合的并發(fā)修改異常解決方案實(shí)例代碼
當(dāng)你遍歷集合的同時(shí),又往集合中添加或者刪除元素,就可能報(bào)并發(fā)修改異常,下面這篇文章主要給大家介紹了關(guān)于Java中遍歷集合的并發(fā)修改異常解決方案的相關(guān)資料,需要的朋友可以參考下2022-12-12詳解mybatis #{}和${}的區(qū)別、傳參、基本語法
這篇文章主要介紹了mybatis #{}和${}的區(qū)別、傳參、基本語法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07深入學(xué)習(xí)MyBatis中的參數(shù)(推薦)
大家日常使用MyBatis經(jīng)常會(huì)遇到一些異常,想要避免參數(shù)引起的錯(cuò)誤,我們需要深入了解參數(shù)。想了解參數(shù),我們首先看MyBatis處理參數(shù)和使用參數(shù)的全部過程。下面這篇文章主要給大家介紹了MyBatis中參數(shù)的的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。2017-06-06idea中acitviti使用acitBPM插件出現(xiàn)亂碼問題及解決方法
這篇文章主要介紹了idea中acitviti使用acitBPM插件出現(xiàn)亂碼問題及解決方法,通過將File Encodings內(nèi)容設(shè)置為UTF-8,本文通過圖文展示,需要的朋友可以參考下2021-06-06java獲取兩個(gè)數(shù)組中不同數(shù)據(jù)的方法
這篇文章主要介紹了java獲取兩個(gè)數(shù)組中不同數(shù)據(jù)的方法,實(shí)例分析了java操作數(shù)組的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-03-03