線性表應用三:約瑟夫環問題
任務描述
約瑟夫環是典型的線性表,可以使用不帶頭結點的迴圈單鏈表進行儲存。本關任務,通過使用不帶頭結點的迴圈電連結串列儲存約瑟夫環,並模擬約瑟夫環的報數出圈過程,得出約瑟夫環出圈序列。輸入n(1<=n<=100)為約瑟夫初始結點個數,輸入m(1<=m<=100)為一輪報數數值,輸出出圈序列。 例:n=9 m=3
相關知識
據說著名猶太曆史學家約瑟夫(Josephus)有過以下的故事:在羅馬人佔領喬塔帕特後,39 個猶太人與約瑟夫及他的朋友躲到一個洞中,39個猶太人決定寧願死也不要被敵人抓到,於是決定了一個自殺方式,41個人排成一個圓圈,由第1個人開始報數,每報數到第3人該人就必須自殺,然後再由下一個重新報數,直到所有人都自殺身亡為止。然而約瑟夫和他的朋友並不想遵從。約瑟夫要他的朋友先假裝遵從,他將朋友與自己安排在第16個與第31個位置,於是逃過了這場死亡遊戲。約瑟夫問題可以抽象為:n 個人圍成一圈 (3<=n<=100)(從零開始編號),從第一個人開始報數,第m個將被殺掉 (1<=m<=n),最後剩下一個,其餘人都將被殺掉 。例如n = 6,m = 5,被殺掉的順序為:4, 3, 5, 1, 2, 0。
程式設計要求
本關的程式設計任務是補全step8/polynomailList.h
檔案中的 createJoselink ()、move ()、deleteNextnode ()、printJoseque()
函式,分別實現約瑟夫環的建立,指標固定步數的移動、後繼結點的刪除、約瑟夫環刪除序列列印,這四個函式的具體說明如下:
// 函式createJoselink:建立包含n個結點(不帶頭結點)的迴圈單鏈,結點的資料值以此是1~n // 引數:n-約瑟夫環初始結點個數 // 返回值:約瑟夫環不帶頭迴圈單鏈表的首個結點指標 node* createJoselink(int t);
// 函式move:指標向前移動step步 // 引數:p-起點指標指向的結點位置,step-指標在迴圈單鏈中向前移動的步數 // 返回值:從p指標所指向的結點位置,向前移動step步後所指向的結點位置 node* move(node* p, int step);
// 函式deleteNextnode:刪除p指標所指向的下一個結點 // 引數:pre-指向待刪除結點的前驅結點(注意:當迴圈單鏈只剩下一個結點時,pre指標指向的結點即待刪除結點) void deleteNextnode(node* pre);
// 函式printJoseque:輸出約瑟夫環刪除序列,編號之間用一個空格隔開 // 引數:n-約瑟夫環初始總人數,m-一輪報數值 void printJoseque(int n, int m);
評測說明
本關中包含兩個檔案分別是: step8/joseLink.h :此檔案為學員檔案,包含不帶頭結點的迴圈單鏈表結構約瑟夫環問題相關處理函式,其中createJoselink () 、move () deleteNextnode ()、printJoseque()為學員待實現函式。 step8/test.cpp:此檔案為評測檔案(含main函式),引用“joseLink.h”,主要用於輸入約瑟夫環初始人數n和一輪報數數值m,並呼叫printJoseque()函式輸出約瑟夫環刪除序列。 (上述兩個檔案可通過點選在程式碼取的右上角資料夾中的step8資料夾中檢視)
輸入輸出說明
輸入約瑟夫環初始人數n(1<=n<=100),輸入一輪報數數值m(1<=m<=100),輸出約瑟夫環元素刪除序列,例如:
測試輸入: 6 5 預測輸出: 5 4 6 2 3 1
測試輸入: 9 3 預測輸出: 3 6 9 4 8 5 2 7 1
test.h
#include "joseLink.h" int main() { int n, m; // 輸入初始總人數n,和一輪報數值m cin >> n >> m; // 輸出約瑟夫出圈序列,兩編號之間用一個空格隔開 printJoseque(n, m); return 0; }
joseLink.h
#include <iostream> using namespace std; //單鏈表結點結構定義 struct node { int data; node* next; // 指標域,指向下一個結點 }; // 函式createJoselink:建立包含n個結點(不帶頭結點)的迴圈單鏈,結點的資料值以此是1~n // 引數:n-約瑟夫環初始結點個數 // 返回值:約瑟夫環不帶頭迴圈單鏈表的首個結點指標 node* createJoselink(int t); // 函式move:指標向前移動step步 // 引數:p-起點指標指向的結點位置,step-指標在迴圈單鏈中向前移動的步數 // 返回值:從p指標所指向的結點位置,向前移動step步後所指向的結點位置 node* move(node* p, int step); // 函式deleteNextnode:刪除p指標所指向的下一個結點 // 引數:pre-指向待刪除結點的前驅結點(注意:當迴圈單鏈只剩下一個結點時,pre指標指向的結點即待刪除結點) void deleteNextnode(node* pre); // 函式printJoseque:輸出約瑟夫環刪除序列,編號之間用一個空格隔開 // 引數:n-約瑟夫環初始總人數,m-一輪報數值 void printJoseque(int n, int m); // 函式delList:刪除連結串列,釋放空間 // 引數:h-連結串列頭指標 void delList(node* h); // 函式printList:輸出連結串列,每個資料之間用一個空格隔開 // 引數:h-連結串列頭指標 //void printList(node* h); void delList(node* h) { node* p = h; //指標p指向頭結點,第一個要刪除的結點 while (p) //這個結點是存在的 { h = h->next; //頭指標h指向下一個結點(下一個結點的地址存在當前結點的指標域中,即h->next中 delete p; //刪除p指向的結點 p = h; //p指向當前的頭結點,即下一個要刪除的結點 } } node *newNode(int data) { node *temp = new node; temp->next = temp; temp->data = data; } node* createJoselink( int t) { // 請在此新增程式碼,補全函式createJoselink /********** Begin *********/ node *p, *q; p = (node*)malloc(sizeof(node)); p->next = NULL; p->next = p; for (int i = 1; i <= t; i++) { q = (node*)malloc(sizeof(node)); q->data = i; q->next = p->next; p->next = q; } return p; /********** End **********/ } node* move(node* p, int step) { // 請在此新增程式碼,補全函式move /********** Begin *********/ for(int i = 0; i < step ; i++) //移動到刪除節點位置 { p = p->next; } return p; /********** End **********/ } void deleteNextnode(node* pre) { // 請在此新增程式碼,補全函式deleteNextnode /********** Begin *********/ node *q = pre->next; pre->next = q->next; free(q); /********** End **********/ } void printJoseque(int n, int m) { // 請在此新增程式碼,補全函式printJoseque /********** Begin *********/ node *head = newNode(1); node *prev = head; for (int i = 2; i <= n; i++) { prev->next = newNode(i); prev = prev->next; } prev->next = head; // Connect last // node to first /* while only one node is left in the linked list*/ node *ptr1 = head, *ptr2 = head; while (ptr1->next != ptr1) { // Find m-th node int count = 1; while (count != m) { ptr2 = ptr1; ptr1 = ptr1->next; count++; } /* Remove the m-th node */ ptr2->next = ptr1->next; printf ("%d ", ptr1->data); free(ptr1); ptr1 = ptr2->next; } printf ("%d ", ptr1->data); /********** End **********/ }