【資料結構】約瑟夫問題(連結串列法)
什麼是約瑟夫問題?
約瑟夫問題:n個人圍成一圈,初始編號從1~n排列,從約定編號為x的人開始報數,數到第m個人出圈,接著又從1開始報數,報到第m個數的人又退出圈,以此類推,最後圈內只剩下一個人,這個人就是贏家,求出贏家的編號。
是不是有點點複雜,其實該問題歸結為模擬型別的演算法題,根據題目要求模擬即可。
環形連結串列
1、先建立一個環形連結串列來存放元素:
2、然後一邊遍歷連結串列一遍刪除,直到連結串列只剩下一個節點,我這裡就不全部演示了
那麼,通過前面對環形連結串列的瞭解,以你的智慧應該會輕鬆解決簡單的約瑟夫問題了。
不妨我們加大難度,設有編號為1,2,3,...,n(n>0)個人按順時針順序圍坐一圈,沒人手持一個隨機產生的密碼(正整數)。現從第k個人開始順時針的方向以1開始報數,報數的上限第一個人持有的密碼m,報到m的人出列,然後將出列的人所持有的密碼作為新的m值,從下一個人開始重新從1開始報數,如此下去,直到最後一個人出列為止,要求設計一個程式模擬此過程,並輸出他們的列編號序列
問題分析
很顯然這是一個線性結構,可以用線性表來表示。進行的主要操作是報數、出列,這個相當於對線性表進行刪除操作,因此宜用用連結串列儲存結構,每個節點表示一個人。n個人圍城一圈迴圈報數,則利用單迴圈連結串列儲存結構更容易解決問題。
因此,
第一步需要建立單迴圈連結串列,每個節點儲存節點序號和密碼,密碼隨機生成(1-10)
第二步實現迴圈刪除操作,將密碼作為每次迴圈的步長(這裡指的是距離)
第三步實現列印操作(跟隨第二步操作)
程式設計
/*單迴圈連結串列的儲存結構*/ typedef struct { int num;//序號 int pwd;//密碼 struct Joseph *next; }Joseph;
輸入設計
在一行中輸入總人數和第幾個人開始報數
輸入設計
首先輸出每個人的編號以及持有的密碼,其次輸出出列的編號次序,最後輸出倖存者。
基本操作
建立連結串列:Joseph* creatList(Joseph* head,int n);
輸出每個人的序號以及密碼:void printList(Joseph* head,int n);
初始從第k個人開始報數,輸出出列次序:void outList(Joseph *head,int k);
程式程式碼
#include <stdio.h> #include <stdlib.h> #include <math.h> #include <malloc.h> /*約瑟夫環問題 *單迴圈連結串列的建立 *列印單迴圈連結串列 *迴圈淘汰m,最後留下倖存者 */ typedef struct { int num; int pwd; struct Joseph *next; }Joseph; Joseph* creatList(Joseph* head,int n) { int i; Joseph *p,*q; q = head; q->num = 1; q->pwd = rand()%10+1; for(i = 2;i<=n;i++) //尾插法 { p = (Joseph*)malloc(sizeof(Joseph)); p->num = i; p->pwd = rand()%10+1; q->next = p; q = p; } p->next = head; } void printList(Joseph* head,int n) { int i; Joseph *list; list = head; for(i = 0;i<n;i++) { printf("第%d位的密碼是%d\n",list->num,list->pwd); list = list->next; } } void outList(Joseph *head,int k) { Joseph *p,*q; q = (Joseph*)malloc(sizeof(Joseph)); p = head; int m; for(int i = 1;i<k;i++) //找第k個節點,作為開始 { q = p; p = p->next; } m = head->pwd; //第k個節點的密碼作為步長(這裡指的是距離) while(p!=q) //當留下最後一個節點時p = q { for(int i = 1;i<m;i++) { q = p; p = p->next; } m = p->pwd; printf("%d ",p->num); q->next = p->next; free(p); p = q->next; } printf("\n倖存者:%d",q->num); free(p); } int main() { Joseph *joseph; joseph = (Joseph*)malloc(sizeof(Joseph)); int n; printf("輸入總人數:"); scanf("%d",&n); creatList(joseph,n); printList(joseph,n); int k; printf("輸入從第幾個人開始報數:"); scanf("%d",&k); outList(joseph,k); return 0; }