循环链表实现约瑟夫环(c语言)
问题描述如下:
编号为1,2…n的n个人按顺时针方向围坐一圈,每人持有一个密码。一开始人选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始报数,报到m时停止报数,报m的人出列,将他的密码作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,直到所有人出列。设计程序求出列顺序。
问题分析:
- 数据结构的选择:
将编号num,密码data,下个人的指针next封装成一个结构体,代表一个“人”。围成一圈可以用循环链表实现,但是尾插法构造链表时尾元结点指向首元结点会避免绕圈时遇到头结点的情况。 - 删除操作与判空操作一同写在main函数中。
若p->next=p则该结点p已经是最后一个人,所以在循环结束后不要忘记最后一个剩下的人。删除操作一定要先找到要删元素的前驱结点,前驱结点指向p->next->next.
完整代码如下:
#define ERROR -1
#define TRUE 1
#define OVERFLOW -1
typedef int Elemtype;
typedef int Status;
typedef struct LNode{
Elemtype data;//密码
int num;//编号
struct LNode *next;
}LNode, *LinkList;
LinkList Initlinklist(LinkList &l){
l=(LinkList)malloc(sizeof(LNode));
l->next=l;
return l;
}
void CreateFromTail(LinkList l){
LinkList r=l, s;
Elemtype c;
int flag=1, k=1;
printf("请输入每个人的密码:\n");
//getchar();
//printf("%c\n", c);
while(flag==1){//先建立节点再设置next
scanf("%d", &c);
if(c!=-1){
s=(LinkList)malloc(sizeof(LNode));
s->data=c;
s->num=k++;
r->next=s;//r指向上一个s;
r=s;
}
else{
flag=0;
r->next=l->next;
}
}
}
int main(){
int m, counter=0;
LinkList l, p, q;
Initlinklist(l);
CreateFromTail(l);
cout<<"请输入初始报数上限值:"<<endl;
cin>>m;
p=l->next;
while(p->next!=p){
counter=1;
while(counter!=m-1){
counter++;
p=p->next;
}
q=p->next;
p->next=q->next;
m=q->data;
cout<<"本次出列的人是:"<<endl;
cout<<q->num<<endl;
p=p->next;
free(q);
}
cout<<"本次出列的人是:"<<endl;
cout<<p->num;
}
效果如下: