([写在前面]这题是数据结构的作业,网上找了半天没找到答案,只好到处借鉴一下,硬搞出来了…)
[问题描述] 设有n个人围坐一圈,现从某个人开始报数,数到m的人出列,接着从出列的下一个人开始重新报数,数到m的人又出列,如此下去,直到所有人都出列为止。试设计确定他们的出列次序序列的程序。
[基本要求] 选择单向循环链表作为存储结构模拟整个过程,并依次输出出列的各人的编号。
(1)根据下面给出的部分源码,理解题意,在有下划线的位置上删除下划线,编写需要的语句,将程序完整化,并要求调试成功。
(2)根据屏幕调试的实际情况填写调试过程
[实现提示] 由于该问题是由古罗马著名史学家Josephus提出的问题演变而来,所以通常称之为Josephus问题。
程序运行之后,首先要求用户指定初始报数的上限值,可以n<=30,此题中循环链表可不设头结点,而且必须注意空表和“非空表”的界限。如:n=8,m=4时,若从第一个人,设每个人的编号依次为1,2,3,…开始报数,则得到的出列次序为4 8 5 2 1 3 7 6,如下图所示,内层数字表示人的编号,每个编号外层的数字代表人出列的序号。
直接上代码
#include "stdlib.h"
#include "stdio.h"
#include <iostream>
#pragma warning (disable:4996)
using namespace std;
/*定义链表的结点*/
typedef struct node
{
int num;
struct node *next;
}Lnode, *Linklist;
/*初始化单向循环链表head*/
void linkinit(Linklist &head)
{
int num = 0;
head = NULL;
}
/*使n个人围成一圈,生成不带头结点的单向循环链表,头指针为head,并给每个人表识号数*/
/*先生成不带头结点的单向链表的方法:在单向循环链表最后一个结点后插入*/
/*最后生成单向循环链表的方法:将最后一个结点的指针指向头指针,形成循环链表*/
Linklist linkcreate(Linklist &head, int n)
{
Linklist s, tail; /* s是指向动态分配新结点的指针,tail是指向链表的最后一个结点的指针*/
int i;
s = (Linklist)malloc(sizeof(Lnode));
if (!s) return head;
s->num = 1;
head = s;
tail = s;
for (i = 2; i <= n; i++)
{
s = (Linklist)malloc(sizeof(Lnode));
if (!s) return head;
s->num = i; /* 将表识号i的值赋给新结点*/
tail->next = s; /* 在tail指针后插入一个新结点*/
tail = s;
}
tail->next = head; /* 最后一个结点的指针指向头指针,形成循环链表*/
return head;
}/*linkcreate*/
/*现从第1结点开始报数,数到m的结点从单向循环链表中删除,并输出结点的编号*/
void linktraverse(Linklist head)
{
Linklist p;
printf("the circle_linklist is :");
printf("%4d", head->num);
p = head->next;
while (p->next != head->next) /* 判断游历p指针是否指向头结点*/
{
printf("%4d", p->num);
p = p->next;
}
printf("\n");
}
Linklist linkselect(Linklist &head, int m)
{
Linklist p, q;
int i, t;
p = head->next;
t = 1;
q = head;/* p是单向循环链表中游历的指针,指向当前报数的结点;q为p的前趋指针*/
p = q->next;
printf("the Joseohus_linklist is :");
while (q != p)
{
t++; /* 累计报一次数*/
if (t%m == 0) /* 数到m的人出列*/
{
printf("%4d", p->num);
cout << endl;
q->next = q->next->next; /* 删除p指向的结点*/
free(p); /* 回收p结点占用的存储空间*/
p = q->next;
//linktraverse(head);
}
else
{
p = p->next; /* p指向当前报数的结点的下一个结点;q为p的前趋指针*/
q = q->next;
}
}
head = p;
return head; /* 返回当前单向循环链表*/
}/*linkselect*/
/*单向循环链表的输出*/
/*主函数main()*/
int main()
{
int n, m;
Linklist head;
printf("\ninput the total number: ");
scanf("%d", &n);
printf("\ninput the number to call: ");
scanf("%d", &m);
linkinit(head);
linkcreate(head, n); /* 调用linkcreate()函数,创建n个结点的单向循环链表*/
if (head == NULL) printf("malloc failure...\n");
else linktraverse(head);
linkselect(head, m); /* 调用linkselect()函数,求解Josephus问题,依次输出出列的各结点的编号*/
printf("\nthe last one is : %d\n", head->num);
}/*main*/