目录
问题
约瑟夫问题 (本题要求用循环链表实现)
约瑟夫问题是一个经典的问题。已知n个人(不妨分别以编号1,2,3,…,n 代表 )围坐在一张圆桌周围,从编号为 k 的人开始,从1开始顺时针报数1, 2, 3, ...,顺时针数到m 的那个人,出列并输出。然后从出列的下一个人开始,从1开始继续顺时针报数,数到m的那个人,出列并输出,…依此重复下去,直到圆桌周围的人全部出列。
输入:n, k, m
输出:按照出列的顺序依次输出出列人的编号,编号中间相隔一个空格,每10个编号为一行。
非法情况
a)
输入::n、k、m任一个小于1
输出:n,m,k must bigger than 0.
b)
输入:k>n
输出:k should not bigger than n.
合法情况
输入:9,3,2
输出:4 6 8 1 3 7 2 9 5
思路
建立一个循环链表, 将最后一个节点的 next 连接到 head->next 上, 形成一个循环。
删掉被叫到的人的节点, 直到只剩下一个人。
代码里名字起的有些随意呜呜, 最好还是规范一点。
代码
#include <cstdio>
#include <iostream>
#include <cstdlib>
using namespace std;
typedef struct Xhlb//循环链表
{
int shu;
struct Xhlb *xia;
}xhlb;
xhlb *tou;
xhlb *chuangjian(int n)//创建链表函数
{
tou = new xhlb;
xhlb *pre = tou;
for(int j = 0; j < n; j++)
{
xhlb *pp = new xhlb;
pp->shu = j+1;
pp->xia = NULL;
pre->xia = pp;
pre = pp;
}
pre->xia = tou->xia;//将首尾相连
return tou;
}
int main()
{
int n, m, k; int i, j, flag = 0, ge = 0;
scanf("%d,%d,%d",&n,&k,&m);
if(n<1 || k<1 || m<1)//非法
{
printf("n,m,k must bigger than 0.\n");
return 0;
}
if(k > n)
{
printf("k should not bigger than n.\n");
return 0;
}
if(n==1) //特殊情况,但乐学似乎没有这个例子
{
printf("1\n");
return 0;
}
if(m==1) //特殊情况,但乐学似乎没有这个例子
{
for(i = 0; i < n; i++)
{
printf("%d",k);
ge++;k++;
if(k>n) k=1;
if(ge==10)
{
printf("\n");ge=0;
}
else
{
printf(" ");
}
}printf("\n");
return 0;
}
ge = 0;
xhlb *biao = chuangjian(n);//创建链表
for(j = 0; j < k; j++)
{
biao = biao->xia;
}
for(i = 0; ; i++)
{
flag++;
if(flag+1 == m)
{
printf("%d",biao->xia->shu);
ge++;
if(ge == 10)
{
printf("\n");ge=0;
}
else
{
printf(" ");
}
xhlb *tem = biao->xia;
biao->xia = biao->xia->xia;
delete tem; //删除被叫到的节点
flag = 0; //重置
biao = biao->xia;
if(biao->shu == biao->xia->shu) break; //是否仅剩一个人
}
else biao = biao->xia;
}
printf("%d\n",biao->xia->shu);
free(biao);
free(tou);
return 0;
}