约瑟夫环问题
(这是一个比较简单的链表入门小练习,记录一下整个学习和代码进步的过程。)
题目:
问题描述为:编号为1,2,3,,,,n的n个人按顺时针方向为坐在一张圆桌周围,每人持有一个密码(整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始报数,报到m时停止报数,报m的那个人出列,将其密码作为新的m值,并从顺时针方向的下一个人开始重新从1报数,数到m的那个人又出列;如此下去,直到圆桌的人全部出列为止。
分析:
算法分析实现,在这里采用单项循环链表的数据结构,因为要进行反复的删除操作;令链表的尾指针指向首元素的地址。每个人的信息作为一个节点,此节点中存储着他们的编号和密码。在下面的代码中,编号我用id表示,密码用了secret(其实是密码的英语单词在写的时候没想起来,,,,,就用了个秘密,,,?),每个节点除了指针域以外,还有两个域存储编号和密码。
思路分析:
- 因为有n个人,所以第一步建立n个节点的单项循环链表。因此我们要写一个创建单链表的函数,输入编号和与之对应的密码,[然后打印出链表(整个的信息),可以选作,为了观察方便,思路更清晰还是写一下比较好~]
- 从链表的第一个节点开始循环找寻下一个节点,即循环到m的那个人。
- 输出该节点的id(对应编号),将该节点的secret(密码)作为新的m值循环下去,并删除该节点。所以此处我们需要写一个根据m值循环获取新节点的函数。
- 根据m值不断从链表中删除节点,直到链表为空。所以我们要有对应的判空操作。
自定义的结构体类型:
typedef struct Node
{
int id; //编号
int secret; //对应密码
struct Node *next;
}Node;
函数:
void Creatlist(Node **,int);
void Printlist(Node *);
Node *GetNode(int ,int);
void Runninglist(Node **,int);
完整代码块
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 50
typedef struct Node
{
int id; //编号
int secret; //对应密码
struct Node *next;
}Node;
void Creatlist(Node **,int);
void Printlist(Node *);
Node *GetNode(int ,int);
void Runninglist(Node **,int);
int main(void)
{
int m,n; //m是初始密码,n为人个数
m=n=0;
Node *pHead =NULL;
do
{
if (n<MAXSIZE)
{
//输入人数
//printf("输入人数");
scanf("%d",&n);
}
}while(n>MAXSIZE);
//printf("输入初始密码");
scanf("%d",&m);
Creatlist(&pHead,n);
Printlist(pHead);
Runninglist(&pHead,m);
return 1;
}
void Creatlist(Node **Head,int n)
{
Node *pNew=NULL; //创建循环链表Head
Node *p=NULL;
int i,Secret;
for (i=1;i<=n;i++)
{
scanf("%d ",&Secret);
pNew=GetNode(i,Secret);
if(*Head==NULL)
{
*Head=p=pNew;
p->next=*Head;
}
else
{
pNew->next=p->next;
p->next=pNew;
p=pNew;
}
}
}
Node *GetNode(int Id,int Secret)
{
Node *pNew=NULL;
pNew=(Node *)malloc(sizeof(Node));
if(!pNew)
{
exit(-1);
}
pNew->id=Id; //传送编号
pNew->secret=Secret;//传密码
pNew->next=NULL;
return pNew;
}
void Printlist(Node *pHead)//打印创建好的链表
{
Node *p;
p=pHead;
if(pHead==NULL) //判读链表是否为空
{
printf("NULL");
}
else
{
do
{
printf("%d",p->secret);
//printf("%d %5d",p->id,p->secret);
p=p->next;
} while(p!=pHead);
}
}
void Runninglist(Node **Head,int Secret) //运行
{
int temp=0,x=1;
Node *pre,*pcur,*pdel; //头尾删除
pre=pcur=pdel=NULL;
pre=pcur=*Head;
while(pre->next!=*Head)
pre=pre->next;
while(x)
{
for(temp=1;temp<Secret;temp++)
{
pre=pcur;
pcur=pcur->next;
}
if(pre==pcur) x=0;
pdel=pcur;
pre->next=pcur->next;
pcur=pcur->next;
Secret=pdel->secret;
//printf("出列");
printf("%d",pdel->id);
//printf("No.%d个人出列,密码是%d\n",pdel->id,pdel->secret);
free(pdel);
}
*Head=NULL;
getchar();
}