这是在《数据结构与算法分析(c描述)》书中的第三章的3.10练习题,是约瑟夫环的问题,
具体描述:有N个人围成一个圆环,每隔M个人后,第M个被淘汰出局,接着从被淘汰出局者的第二个人开始重新计数计算再次计算M个!
程序结束条件是当环中只剩下一个人的时候程序就可已结束,并且输出被淘汰的人的编号,以及胜利者的编号。
解决这个问题的关键是:1、对链表的基本操作需比较熟悉!
2、搭建一个循环的单链表!
3、每次删除一个节点的时候需要跳到他的下一个节点!
4、注意一些特殊的位置!比如最后一个节点。
5、当程序还剩下两个人的时候会出现一些bug,本次程序解决了这些bug。
程序代码如下,只为给新人解解迷惑,高手请多多指点!
#include <stdio.h>
#include <stdlib.h>
/*
** 2015年05月10日 12:28:45
**
**
**
**
**
**
** 关键是在删除到后面只有两个元素的时候那么就会出现错,会多走一步!
*/
#define Test 0
//struct of Josephus
typedef struct Josephus
{
int number;
struct Josephus *next;
}jp;
typedef jp * Jptr;
void
creat_link( Jptr *head , int n )
{
int i = 1;
Jptr p,tail;
tail->next = NULL;
(*head) = tail;
while( i <= n )
{
p = ( Jptr )malloc( sizeof( jp ) );
if( !p )
{
printf(“Sorry,没有可用的内存供您使用程序将退出!”);
exit(0);
}
printf(“请输入第%d个人的编号\n”,i);
scanf(“%d”,&p->number);
tail->next = p;
p->next = NULL;
tail = p;
i++;
}
tail->next = *head;
}
void
output_link( Jptr *head )
{
if( *head == NULL )
{
printf(“The head pointer is NULL !\n”);
exit(0);
}
Jptr p = *head;
while( p->next != *head )
{
p = p->next;
printf(“%d “,p->number);
}
putchar(‘\n’);
}
void
Run( Jptr * head ,int m,int n )
{
int count = 0;
Jptr p = (*head)->next;
Jptr pre = *head;
while( n > 1 )
{
if( count == m )
{
printf(“%d被淘汰\n”,p->number);
pre->next = p->next;
free(p);
p = pre->next;
n–;
count = 0;
continue;
}
count++;
p = p->next;
pre = pre->next;
if( p == *head )
{
p = p->next;
pre = *head;
}
//在程序执行到只剩下两个人的时候会出现一个bug下面这条语句是为了防止这个bug让程序偷了一步!
if( n == 2 && pre == *head )
count++;
}
printf(“%d是赢家!\n”,(*head)->next->number);
}
int
main(void)
{
Jptr head;
int m,n;
printf(“请输入传递次数m以及参与人数n\n”);
scanf(“%d%d”,&m,&n);
creat_link(&head,n);
Run(&head,m,n);
//test
#if Test
output_link(&head);
#endif
return 0;
}