C++实现约瑟夫问题:顺序存储与链表解法

5星 · 超过95%的资源 需积分: 15 3 下载量 131 浏览量 更新于2024-09-16 收藏 4KB TXT 举报
"约瑟夫问题的两种求解方法,主要涉及顺序存储和链表的实现。提供的代码示例是用C++语言实现的链表版本。" 约瑟夫问题是一个经典的理论问题,通常用于考察计算机算法设计和数据结构的应用。问题描述如下:n个人围成一个圈,从某个人开始按顺时针方向报数,每报到第m个人就被淘汰出局,然后从下一个人继续报数,直至只剩最后一个人为止。这个最后剩下的人被称为“约瑟夫幸存者”。 本问题的两种求解方法如下: 1. **顺序存储**:这种方法通常使用数组来表示环形结构,数组的下标代表人的编号。每次淘汰操作可以通过简单的数学计算完成,但缺点是数组长度固定,如果n非常大,会浪费大量空间。 2. **链表存储**:链表更适合模拟环形结构,每个节点代表一个人,包含编号(order)和特定值(key),如代码所示。链表头节点的next和previous指针指向自身,形成环状。这种方法更灵活,可以适应动态变化的n值,但操作相对复杂,需要额外的内存分配和指针操作。 在给出的代码中,定义了一个`LinkList`结构体,其中包含了`order`(编号)和`key`(密码或特定值)以及两个指针`next`和`previous`。`CreateLink`函数用于创建链表,并根据用户输入填充每个节点的`key`值。`JudgeCode`函数用于判断是否需要输入节点的`key`值,`flag`变量控制这一行为。 链表的创建过程如下: 1. 分配一个新节点作为链表的头节点,并设置其`order`、`next`和`previous`指针。 2. 如果需要输入密码,读取并存储头节点的`key`值。 3. 遍历从2到n,为每个位置创建新的节点,将其插入链表,并更新相应指针。 4. 如果需要输入密码,为每个新创建的节点读取并存储`key`值。 通过这种方式,链表可以方便地进行报数和淘汰操作,每次报数时遍历链表,淘汰第m个节点,然后更新链表结构。最后剩下的节点就是约瑟夫幸存者。 总结来说,解决约瑟夫问题的两种方法各有优缺点,顺序存储简单但不灵活,链表存储灵活但操作复杂。实际应用中,可以根据问题规模和需求选择合适的方法。
2007-04-04 上传
约瑟夫问题全集 據說著名猶太歷史學家 Josephus有過以下的故事:在羅馬人佔領喬塔帕特後,39 個猶太人與Josephus及他的朋友躲到一個洞中,39個猶太人決定寧願死也不要被敵人到,於是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下一個重新報數,直到所有人都自殺身亡為止。 然而Josephus 和他的朋友並不想遵從,Josephus要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。 約瑟夫問題可用代數分析來求解,將這個問題擴大好了,假設現在您與m個朋友不幸參與了這個遊戲,您要如何保護您與您的朋友?只要畫兩個圓圈就可以讓自己與朋友免於死亡遊戲,這兩個圓圈內圈是排列順序,而外圈是自殺順序,如下圖所示: 使用程式來求解的話,只要將陣列當作環狀來處理就可以了,在陣列中由計數1開始,每找到三個無資料區就填入一個計數,直而計數達41為止,然後將陣列由索引1開始列出,就可以得知每個位置的自殺順序,這就是約瑟夫排列,41個人而報數3的約琴夫排列如下所示: 14 36 1 38 15 2 24 30 3 16 34 4 25 17 5 40 31 6 18 26 7 37 19 8 35 27 9 20 32 10 41 21 11 28 39 12 22 33 13 29 23 由上可知,最後一個自殺的是在第31個位置,而倒數第二個自殺的要排在第16個位置,之前的人都死光了,所以他們也就不知道約琴夫與他的朋友並沒有遵守遊戲規則了。 c #include <stdio.h> #include <stdlib.h> #define N 41 #define M 3 int main(void) { int man[N] = {0}; int count = 1; int i = 0, pos = -1; int alive = 0; while(count <= N) { do { pos = (pos+1) % N; // 環狀處理 if(man[pos] == 0) i++; if(i == M) { // 報數為3了 i = 0; break; } } while(1); man[pos] = count; count++; } printf(\"\\n約琴夫排列:\"); for(i = 0; i < N; i++) printf(\"%d \", man[i]); printf(\"\\n\\n您想要救多少人?\"); scanf(\"%d\", &alive); printf(\"\\nL表示這%d人要放的位置:\\n\", alive); for(i = 0; i < N; i++) { if(man[i] > alive) printf(\"D\"); else printf(\"L\"); if((i+1) % 5 == 0) printf(\" \"); } p rintf(\"\\n\"); return 0; } java public class Josephus { public static int[] arrayOfJosephus( int number, int per) { int[] man = new int[number]; for(int count = 1, i = 0, pos = -1; count <= number; count++) { do { pos = (pos+1) % number; // 環狀處理 if(man[pos] == 0) i++; i f(i == per) { // 報數為3了 i = 0; break; } } while(true); man[pos] = count; } return man; } public static void main(String[] args) { int[] man = Josephus.arrayOfJosephus(41, 3); int alive = 3; System.out.println(\"約琴夫排列:\"); for(int i = 0; i < 41; i++) System.out.print(man[i] + \" \"); System.out.println(\"\\nL表示3個存活的人要放的位置:\"); for(int i = 0; i < 41; i++) { if(man[i] > alive) System.out.print(\"D\"); else System.out.print(\"L\"); if((i+1) % 5 == 0) System.out.print(\" \"); } System.out.println(); }}