/* 利用雙向鏈表解決約瑟夫環問題(也可以使用循環鏈表) 問題描述: 將n個人圍成一圈開始報數,每次報到m的人出列,它的下一個 人從1開始重新報數,直到所有玩家出列。 解決思路,使用一個雙向循環鏈表模擬整個游戲成員,每一個節點 代表一玩家。 */ # include <stdio.h> # include <stdlib.h> # include <malloc.h> // 雙向鏈表類型定義 typedef struct NODE { int data; // 數據域 struct NODE * next; // 儲存前驅地址 struct NODE * prior; // 儲存此節點的后一個節點的地址 }Node, * pNode; // 雙向循環鏈表的創建 pNode Create_DCList(int len); // 在長度為n的雙向循環鏈表上,報數為m的玩家出列 void Josephus(pNode pHead, int n, int m, int k); int main(void) { pNode pHead; int n, k, m; printf("輸入玩家個數 n = "); scanf("%d", &n); printf("輸入開始報數的序號 k = "); scanf("%d", &k); printf("報數為 m 的人出列 m = "); scanf("%d", &m); pHead = Create_DCList(n); Josephus(pHead, n, m, k); return 0; } // 雙向循環鏈表的創建 pNode Create_DCList(int len) { pNode pHead = NULL; pNode s, q; int i; for (i = 1; i <= len; ++i) { s = (pNode)malloc(sizeof(Node)); if (NULL == s) { printf("動態內存分配失敗!\n"); exit(-1); } s->data = i; s->next = NULL; // 將新節點插入雙向循環鏈表 if (NULL == pHead) { pHead = s; s->prior = pHead; s->next = pHead; } else { s->next = q->next; q->next = s; s->prior = q; pHead->prior = s; } // q始終指向鏈表最后一個節點 q = s; } return pHead; } // 在長度為n的雙向循環鏈表上,報數為m的玩家出列 void Josephus(pNode pHead, int n, int m, int k) { pNode p, q; int i; p = pHead; // 從第k個人開始報數 for (i = 1; i < k; ++i) { q = p; p = p->next; } while (p->next != p) // 當只剩下一個節點時停止循環 { for (i = 1; i < m; ++i) { q = p; p = p->next; } q->next = p->next; // 將p節點刪除 p->next->prior = q; printf("%4d", p->data); // 輸出出列的玩家 free(p); p = q->next; } printf("%4d\n", p->data); free(p); p = NULL; return; }