实验一
• 采用单向环表实现约瑟夫环。
• 请按以下要求编程实现:
• 从键盘输入整数m,通过create函数生成一个具有m个结点的单向环表。环表中的结点编号依次为1,2,……,m。
• 从键盘输入整数s(1<=s<=m)和n,从环表的第s个结点开始计数为1,当计数到第n个结点时,输出该第n结点对应的编号,将该结点从环表中消除,从输出结点的下一个结点开始重新计数到n,这样,不断进行计数,不断进行输出,直到输出了这个环表的全部结点为止。
• 循环链表(带有头结点的单向环表)
最后一个结点的指针域的指针又指回第一个结点(头结点)的链表。
与单向链表的差别仅在于,判别链表中最后一
个结点的条件不再是 “ 后继是否为空 ” ,而是 “ 后
继是否为头结点 ”。
• 循环链表的特点
- 从一个结点可找到链表中的任意一个结点;
- 判断是否为表尾结点的条件:p->next == L。
- 有时,用表尾指针表示循环链表
实现链表如下:
//约瑟夫环.cpp
#include<stdio.h>
#include<malloc.h>
struct node
{
int data;
struct node* next;
};
struct node *p,*q,*head,*tail;
void create(int m,int n,struct node* head)
{
if(m<=0||n>m)
{
free(head);
printf("ERROR!");
}
else
{
int i=1;
tail=head;
for(i=1;i<=m;i++)
{
p=(struct node* )malloc(sizeof(struct node));
p->data=i;
tail->next=p;//用tail表示当前链表中最后一个结点
p->next=head->next;//形成循环
tail=p;
}
p=p->next;//把p指到首元结点
}
}
int main()
{
int m;//链表有m个结点
int s,n;//从第s个结点开始计数为1
int count=1;//记录共输出了多少个数
int flag=0;//记录数到了1~n中的第几个结点
int i;//用于各种循环
printf("请按照形式“m s n”输入链表结点个数、开始节点及循环数:");
scanf("%d %d %d",&m,&s,&n);
head=(struct node* )malloc(sizeof(struct node));//头结点
head->data=-1,head->next=NULL;//初始化
create(m,s,head);//建立有m个结点的循环链表
p=head->next;
q=tail;//初始化
for(i=1;i<s;i++)
{
p=p->next;
q=q->next;
}//让p指在第s个结点上
while(count<=m)
{
for(flag=1;flag<n;flag++)
{
p=p->next;
q=q->next;
}
printf("%d ",p->data);
q->next=q->next->next;
free(p);//将输出过的节点删除并释放相应内存
p=q->next;
count++;
}
return 0;
}