千家信息网

Josephus问题的不同实现方法与总结

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,1 /************************************************************************/ 2 /*
千家信息网最后更新 2026年11月01日Josephus问题的不同实现方法与总结

  1 /************************************************************************/  2 /*                   Josephus问题--数组实现                           */  3 /************************************************************************/  4 #include   5 #include   6   7 int Josephus(int times, int number, int id){  8     int *a;  9     int i, count = 0, t = 0;  10     a = (int *)malloc(sizeof(int) * number); 11  12     for(i = 0; i < number; i++) 13         a[i] = i + 1;             // 数组a用于储存每个元素的编号 14     i = id - 1; 15  16     while(count < number - 1){ 17         if(a[i] != 0) 18             t++; 19         if(t == times){ 20             t = 0;  21             count++; 22             printf("%4d", a[i]); 23             a[i] = 0;                // 当该元素被剔除时,该数组元素置为0 24         } 25         i++; 26         if(i == number) 27             i = 0; 28     } 29     for(i=0;i 62 #include  63  64 typedef struct LNode 65 { 66     int data; 67     struct LNode *next; 68 }LNode,*Linkhead; 69 void Josephus(int m,int n,int k) 70 { 71     Linkhead p,r,head = NULL; 72     int i; 73     for(i = 1;i <= n;i++) 74     { 75         p = (Linkhead)malloc(sizeof(LNode));//申请一个新的链结点 76         p->data = i;//存放第i个结点的编号 77         if(head == NULL) 78             head = p; 79         else 80             r->next = p;      // 因为Insert和Del操作都需要之前一个节点的地址,故用r来存储。其作用类似栈的top 81         r = p; 82     } 83     p->next = head;//至此,建立一个循环链表 84  85     p = head; 86     for(i = 1;i < k;i++) 87     { 88         r=p; 89         /*请注意,此行不是多余的,因为当k!=1,但m=1时如果没有这条语句,此时删除动作无法完成*/ 90         p=p->next; 91     }        //此时p指向第1个出发结点 92  93     while(p->next != p) 94     { 95         for(i = 1;i < m;i++) 96         { 97             r = p; 98             p = p->next; 99         }                        //p指向第m个结点,r指向第m-1个结点100         r->next = p->next;        //删除第m个结点101         printf("%4d",p->data);    //依次输出删除结点的编号102         free(p);                //释放被删除结点的空间103         p = r->next;            //p指向新的出发结点104     }105     printf("\n最后剩余的结点是:%4d\n",p->data);//输出最后一个结点的编号106 }107 108 int main(){109     int times, number, id;110     printf("请输入总人数:");111     scanf("%d", &number);112     printf("请输入报数周期:");113     scanf("%d", ×);114     printf("请输入开始报数的编号:");115     scanf("%d", &id);116     Josephus(times, number, id);117 118     return 0;119 }120 121 /************************************************************************/122 /* 总结:123         优点为可以得出每次被剔除的元素编号124         缺点为相较数组方法需要更多的计算量125         总体而言与数组方法相差无几                                        */126 /************************************************************************/127 128 /************************************************************************/129 /*             Josephus问题--数学归纳法直接计算                       */130 /************************************************************************/131 #include 132 int main() {  133     int answer = 0;  134     int times, number, i, id;    // number为环内总元素个数,times为报数周期, id为从第几个元素开始报数135     printf("请分别输入总人数和循环次数:");136     scanf("%d %d", &number, ×);137     printf("起始报号者的编号:");138     scanf("%d", &id);139     for(i = 1; i <= number; i++) {  140         answer = (answer + times) % i;      // 核心算法,利用数学归纳法得出141     }142     if(answer + id == number)143         printf("Survial: %d\n", number);    // 防止当幸存者为最后一个编号时输出0的情况144     else145         printf("Survival: %d\n",(answer + id) % number);  146         // 这边利用number对answer进行取余操作以防止编号数值超过最大编号(溢出)147     148     return 0;149 }

                                           对于Josephus问题有两个地方是可以进行优化的。 (总人数为N,编号为从0~N-1;经过M次报数去除一个成员,剩余成员个数为numleft, 记M%numleft为mPrime)

 1、被移除的成员离上一个成员之间的距离是M%numleft-1(报数次为M%numleft).当M大于N时,该计算方式将节省大量时间
2、当mPrime大于numleft的时候可以反向遍历该表来查找要去除的成员。这样可以节省时间。同样这也就要求了该表必须是一个双向表才行。(即含有Previous方法)
 该算法实现原理即为:

  第一轮,必定为编号M%N-1的成员被去除,第二轮为在第一轮的基础上即从编号为M%N的成员开始正移mPrime-1个单位(或者反移numleft-mPrime-1个单位)。若将M%N即为编号0,开始重新编号,那么第二轮被删除的成员编号便是M%(numleft)-1,由此可得该轮要被删除的成员与上一轮去除成员之间的距离为M%numleft,这里可利用迭代器来实现。

  这里我们便可以得到成员编号与该轮成员数目的关系是:(n表示该轮所剩余的成员数目,Index(n)表示该轮成员的编号(从0开始))   Index(n) = (Index(n - 1) + m) % n。    那么按照这个过程,我们这样一直移除元素下去,肯定能够找到最后一个被移除的元素。    这个元素则对应只有一个元素的环,很显然,它的值为0。也就是Index(1) = 0。    对于这个元素的索引,它对应两个元素的索引是多少呢?   按照前面的过程,我们倒推回去就是了。Index(2) = (Index(1) + m) % 2。   那么对应3个,4个元素的呢?我们这样一路继续下去就可以找到对应到n个元素的索引了。    所以,我们发现了一个有意思的数学归纳关系:    f(1) = 0,  f(n) = (f(n - 1) + m) % n。    按照这个关系,我们可以得到最后一个被取出来的元素对应到n个元素的环里的索引值。 

至此,我们可以发现,利用count计数从而删除成员的方法与此相比起来逊色不少,故之后我们将采用此方法来解决问题。


元素 成员 结点 输入 问题 数组 方法 人数 指向 数学 索引 剩余 周期 归纳法 数学归纳法 一轮 输出 两个 个数 之间 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 江苏根荣互联网科技 互联网和科技技术 疫情对互联网科技公司影响 没上市的科技互联网公司 广州互联网科技公司 互联网金融公司科技 未来的互联网科技 腾讯科技 互联网女皇 睿民互联网科技 互联网科技logo设计 上海电发互联网科技有限公司 哈尔滨新华互联网科技学院 想开互联网科技公司怎么样 华中科技大学互联网的牛人 互联网企业科技类企业如何做账 上海创道互联网络科技有限公司 从那以后互联网科技有限公司 广东鹅鹅鹅互联网科技有限公司 张家口科技产业互联网平台 承德科技产业互联网平台 互联网科技有限公司 中国互联网科技工作委员会毛军 重生之互联网科技帝国 远拓互联网科技 广州善班互联网科技 互联网科技股有哪些 互联网科技大赛获奖感言 合肥互联网科技公司公章图片 伍佰万互联网科技怎么赚钱 科技发展第三阶段互联网时代
0