不知道大家是否还记得这样一个游戏,一群人,手拉手站成一个环,从第一个人开始报数,可以以三个数为一轮,也就是1,2,3,1,2,3......这样去报,喊到3的人淘汰,其左右两个人再手拉着手,游戏继续进行。就这样一直下去,直到最后只剩一个人,那个人即为胜者。
其实现实生活中好像根本没人玩这个游戏,但是C语言老师上课提到了这么一个问题,是在讲链表的时候。事实上,在总人数和报数确定了之后,剩下的那个人是几号其实已经产生了,比如说,16个人,三个数为一轮,那么最后剩下的肯定是8号。虽然没什么现实意义,但是作为学者来讲,还是个练习数据结构的好机会,所以我把这个题记录下来。
算法非常的简单,就是一个首尾相接的链表,也就是环链表。当初始化给每一个附上数值之后,就可以用一个while函数加上一个if语句进行淘汰。但是要注意的是,整个游戏结束的标志是只剩一个节点,但此时还是一个环,所以也就是该节点的下一个节点是它本身。
我写的程序中,是在预编译中将人数设置为了50,还是三个数为一轮,具体代码如下(C语言):
#include<stdlib.h>
#include<stdio.h>
#define M 50
#define N 3
struct node{
int num;
struct node* next;
};
struct node*init(struct node *head){//构造函数
/*返回的是与节点相同类型的指针*/
struct node *p, *q;
int i;
p = (struct node *)malloc(sizeof(struct node));
p->num = 1;
head = p;
for (i = 2; i < M; i++){
q = (struct node *)malloc(sizeof(struct node));
p->next = q;
q->num = i;
p = q;
}
q = (struct node *)malloc(sizeof(struct node));
p->next = q;
q->num = M;
q->next = head;//如果此值为null则为单链表,若为head 则为环
return head;
}
void print(struct node*head)/*出以head为头的链表各节点的值*/
{
struct node *temp;
temp = head;/*取得链表的头指针*/
while (temp != NULL)/*只要是非空表*/
{
printf("%6d", temp->num);/*输出链表节点的值*/
temp = temp->next;/*跟踪链表增长*/
}
}
struct node*elim(struct node *head){//淘汰函数
struct node *p, *q;
p = head;
q = p->next;
int count = 1;//count用来记录报号
while (q->next != q){
count++;
if (count == N){//如果报号为N,则删除该节点
p->next = q->next;
q = p->next;
count = 1;
}
p = q;
q = q->next;
}
return q;
}
void main(){
struct node *head = NULL;//创建单链表
head = init(head);//创建单链表,环
// print(head);//打印输出
struct node *remain = elim(head);
printf("%d", remain->num);
system("pause");
}
最终输出的结果是11。