今天给大家讲讲约瑟夫问题是什么,并且我提供了一种约瑟夫问题的解决办法。对于不知道约瑟夫是谁的人来说,就更不用提什么是约瑟夫问题了。那么问题来了,约瑟夫是谁,约瑟夫问题又是个什么东西。
首先来个解释吧,约瑟夫问题,有时也称为约瑟夫置换,是一个出现在计算机科学和数学中的问题。特别是对于学习过数据结构的人来说,在书上看到解决这个问题的题目,可能都不下5遍吧。在计算机编程的算法中,类似的问题又称为约瑟夫环或者丢手绢问题。
约瑟夫(Josephus)是谁,约瑟夫是著名的犹太历史学家,那么约瑟夫问题又是个什么东西呢。其实我并不太清楚约瑟夫的什么生平经历,但是关于约瑟夫问题,倒是有一个小故事给大家讲一讲,这个故事就是约瑟夫问题的原型。好了,下面来个大家讲故事了,据说在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
从上面的故事,大家至少可以知道,约瑟夫虽然是个历史学家,但是他的数学学的也不赖嘛。
约瑟夫问题并不难,求解的方法也非常的多,我这里提供一个循环链表的解决方法,为什么用循环链表,因为我看那个故事里面的人都是手拉手围成一个圆圈的嘛。
下面是我写的程序源代码,大家看看,就知道是怎么解决的了:
注:可以通过修改mian()
函数中的Start
,Count
,length
这3个参数来改变游戏的规则,大家可以试试。
#include
#include /* *功能:约瑟夫问题解决办法(循环链表解决) *By:AilsonJack *Date:2014.05.24 */ #defineerror0 #defineok1 typedefintElementType; typedefstructCycleListNodeNode; typedefstructCycleListNode*ptrNode; structCycleListNode//循环链表结点 { ElementTypedata;//数据区 ptrNodenext;//指向下一个结点 }; //函数声明 //约瑟夫问题解决办法(循环链表解决) voidJosephus(ptrNodelist,intstart,intcount,intlength); //创建循环链表头结点 intCycleList_CreateNode(ptrNode*list); //初始化循环链表,并且最后丢掉链表头结点,链表的数据为1->length voidCycleList_Init(ptrNode*list,intlength); //删掉循环链表中从表头数的第position个位置的数据 //最终将头结点变为删除前那个结点的下一个结点 voidCycleList_Delete(ptrNode*list,intposition); //查找循环链表中数据元素是Start的结点的位置,并且将该节点设为新的起始结点s voidCycleList_Find(ptrNode*list,ElementTypeStart); //打印循环链表中的数据 voidPrin_CycleList(ptrNodelist,intlength); intmain(void) { intStart=1;//起始计数位置 intCount=3;//第Count个位置的结点出局 intlength=41;//循环链表的长度 ptrNodelist; CycleList_CreateNode(&list); CycleList_Init(&list,length); Prin_CycleList(list,length); Josephus(list,Start,Count,length); while(1) { } return0; } //约瑟夫问题解决办法(循环链表解决) voidJosephus(ptrNodelist,intstart,intcount,intlength) { inti=1; CycleList_Find(&list,start); printf(" 约瑟夫问题解决开始.... "); while(i<= length) { CycleList_Delete(&list,count); i++; } printf(" 约瑟夫问题解决结束 "); } //创建循环链表头结点 intCycleList_CreateNode(ptrNode*list) { *list=(ptrNode)malloc(sizeof(structCycleListNode)); if(*list==NULL) { printf("OutofSpace... "); returnerror; } (*list)->next=NULL; returnok; } //初始化循环链表,并且最后丢掉链表头结点,链表的数据为1->length voidCycleList_Init(ptrNode*list,intlength) { inti=1; ptrNodenewNode; ptrNodeFirstNode; FirstNode=*list; while(i<= length)//i从1到length { newNode=(ptrNode)malloc(sizeof(structCycleListNode)); newNode->data=i; (*list)->next=newNode; (*list)=newNode; i++; } (*list)->next=FirstNode->next; *list=FirstNode->next; } //删掉循环链表中从表头数的第position个位置的数据 //最终将头结点变为删除前那个结点的下一个结点 voidCycleList_Delete(ptrNode*list,intposition) { inti=1; ptrNodetmp; if(position==1) { tmp=*list; while(tmp->data!=(*list)->next->data) { *list=(*list)->next; } printf("%d",(*list)->next->data); (*list)->next=tmp->next; *list=tmp->next; free(tmp); tmp=NULL; } else { while(i< (position-1)) { (*list)=(*list)->next; i++; } tmp=(*list)->next; printf("%d",tmp->data); (*list)->next=(*list)->next->next; free(tmp); tmp=NULL; *list=(*list)->next; } } //查找循环链表中数据元素是Start的结点的位置,并且将该节点设为新的起始结点 voidCycleList_Find(ptrNode*list,ElementTypeStart) { while((*list)->data!=Start) { *list=(*list)->next; } } //打印循环链表中的数据 voidPrin_CycleList(ptrNodelist,intlength) { inti=1; printf("打印循环链表... "); while(i<= length) { printf("%d",list->data); list=list->next; i++; } printf(" 结束打印 "); }
下面是程序的运行结果:
2015-03-31_165155
以上就是对约瑟夫问题的解决方法啦,大家有不明白的可以留言哟。
-
C语言
+关注
关注
180文章
7604浏览量
136764 -
函数
+关注
关注
3文章
4329浏览量
62588 -
数据结构
+关注
关注
3文章
573浏览量
40127
原文标题:C语言-有趣的约瑟夫问题及解决办法
文章出处:【微信号:嵌入式那些事,微信公众号:嵌入式那些事】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论