最近在做数据结构的助教,给大二的小盆友讲解数据结构实验,第一次实验为线性表及其应用,其中实验内容肯定就是著名的约瑟夫问题了,写这个博客的原因就是帮助刚开始接触数据结构的初学者们更好的理解链表,我主要就是分析代码,并且给出的代码都是通俗易懂的,希望大家看完后能够有所收获,废话不多说,上题。
设有n个人围坐在圆桌周围,现从某个位置m(1<=m<=n)上的人开始报数,报数到k的人就站出来。下一个人,即原来的第k+1个位置上的人,又从一开始报数,再报到k的人站出来。依次重复下去,直到全部的人都站出来为止。试设计一个程序求出列序列。
代码解答如下:
<span style="font-size:18px;">
#include <stdio.h>
#include <stdlib.h>
#define NULL 0
#define OK 1
#define ERROR 0
#define OVERFLOW -2
typedef int Status;
typedef int Elemtype;
typedef struct Cnode
{
Elemtype data;
struct Cnode *next;
}CNode;
CNode *joseph; //定义一个全局变量
Status Cteate_clist(CNode *clist, int n)
{
//clist相当于一个移动的头结点,每次指向生成的最新的结点
CNode *p, *q;
q = NULL;
int i;
clist = NULL;
for (i = n; i >= 1; i--)
{
p = (CNode *)malloc(sizeof(CNode));
if (p == NULL)
{
return OVERFLOW;//内存分配失败
}
p->data = i;//给数据域赋值
p->next = clist;//把生成的结点接在链表上
clist = p;//同时移动clist,使得它总指向最新的结点
if (i == n)
q = p;//用q指向链表的最后一个结点,暂时存储的作用
}
q->next = clist;//把链表的最后一个结点的链域指向链表的第一个结点,构成循环链表
joseph = clist;//把创建好的循环链表的头指针赋给全局变量
return OK;
}
Status Joseph(CNode *clist, int m, int n, int k)
{
//n总人数,m起始位置,k报到k的人站出来
int i;
CNode *p, *q;
if (m > n)
return ERROR;//起始位置错误
p = joseph;
for (i = 1; i < m; i++)//循环m-1次
{
p = p->next;//使p指向m
}
while (p)
{
for (int i = 1; i < k - 1; i++)//循环k-2次,使p指向第k-1个结点
{
p = p->next;
}
q = p->next;//q指向第k个结点
printf("%d ", q->data);
if (p->next == p)
{
p = NULL;
}
else
{
p->next = q->next;
p = p->next;
free(q);
}
}
clist = NULL;
return OK;
}
void main()
{
int m, n, k;
CNode *clist;
clist = NULL;
printf("\n请输入圆桌的总人数n:");
scanf("%d", &n);
printf("\n请输入第一次开始报数的人的位置m:");
scanf("%d", &m);
printf("\n你希望报数到第几个数的人出列?");
scanf("%d", &k);
Cteate_clist(clist, n);
printf("\n出列的顺序如下:\n");
Joseph(clist, m, n, k);
system("pause");
}</span>
运行结果如下: