一个小笔记(3):约瑟夫环
什么是约瑟夫环?
其实百度有说
http://baike.baidu.com/view/717633.htm
以一个传说中的问题为例子,提供源代码
主要是能够通过这个问题,了解如何来操作循环链表
在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏
最后输出结果为最后一个存活的人的编号
// 约瑟夫问题(循环链表).cpp // Win32控制台程序 #include "stdafx.h" #include <stdlib.h> typedef struct JOSEPH_NODE { int iNum; // 编号 struct JOSEPH_NODE * pNext; } JOSEPH_NODE_S; // pJosephStart结点的下一个结点就是要杀死的人,删除该结点 void Delete_Next_Joseph(JOSEPH_NODE_S * pJosephStart) { JOSEPH_NODE_S * pJose = pJosephStart->pNext; pJosephStart->pNext = pJose->pNext; free(pJose); } // 释放链表 void Destroy_Joseph(JOSEPH_NODE_S * pJosephHead) { while (pJosephHead->pNext != pJosephHead) { Destroy_Joseph(pJosephHead); } free(pJosephHead); } // 初始化链表 int Init_Joseph(int iCount, JOSEPH_NODE_S ** ppJosephHead) { if (iCount < 1) { return 0; } JOSEPH_NODE_S * pJoseNew; JOSEPH_NODE_S * pJoseCur; int iSize = sizeof(JOSEPH_NODE_S); pJoseNew = (JOSEPH_NODE_S *)malloc(iSize); if (pJoseNew == nullptr) { return 0; } pJoseNew->iNum = 1; pJoseNew->pNext = pJoseNew; *ppJosephHead = pJoseNew; pJoseCur = pJoseNew; // 链表添加结点 for (int i = 1; i < iCount; i++) { pJoseNew = (JOSEPH_NODE_S *)malloc(iSize); if (pJoseNew == nullptr) { Destroy_Joseph(*ppJosephHead); return 0; } pJoseNew->iNum = i + 1; pJoseNew->pNext = *ppJosephHead; pJoseCur->pNext = pJoseNew; pJoseCur = pJoseNew; } return 1; } // 得到最后一个存活的人 // iCount:总人数 // iSkip:每隔多少个人就杀死一个人 int GetLastNode_Joseph(int iCount, int iSkip) { JOSEPH_NODE_S * pJoseph = nullptr; JOSEPH_NODE_S * pJoseStart = nullptr; if (Init_Joseph(iCount, &pJoseph) != 1) { printf("初始化失败\n"); return 0; } pJoseStart = pJoseph; // 每隔0个人杀死,最后一个人存活 if (iSkip == 0) { while (pJoseStart->pNext->pNext != pJoseStart) { Delete_Next_Joseph(pJoseStart); } printf("Final Num: %d\n\n", pJoseStart->pNext->iNum); free(pJoseStart->pNext); free(pJoseStart); return 1; } // 每隔iSkip个人杀死一个人 // 直到剩下1个人,剩下最后一个结点的pNext会指向自己 while (pJoseStart->pNext != pJoseStart) { for (int i = 1; i < iSkip; i++) { pJoseStart = pJoseStart->pNext; } Delete_Next_Joseph(pJoseStart); pJoseStart = pJoseStart->pNext; } printf("Final Num: %d\n\n", pJoseStart->iNum); free(pJoseStart); return 1; } int main() { GetLastNode_Joseph(41, 2); return 0; }