版权声明:欢迎朋友们的观摩,标注原创的文章,如应用,请标明出处,谢谢。 https://blog.csdn.net/qq_37012770/article/details/78079992
在罗马人占领桥塔帕特之后,39人和约瑟夫以及他的朋友躲到一个山洞里,39个犹太人宁愿死,也不愿意被抓,于是他们想到一个自杀的方式:41人排成一圈,由第一个人开始报数,每数到三,该人就必须自杀,然后由下一个人再开始报数,直到所有人都自杀身亡为止。怎样安排顺序才能让约瑟夫和他的朋友活到最后呢?
这是一个循环链表的经典问题
顺便将之前学的不太扎实的链表的创建、元素删除一并练习了
#include<stdio.h>
#include<stdlib.h>
typedef struct node{
/**结构体定义了一个节点data就是节点数据域,*next就是节点的指针域。
用一个结构,整出链表要用到的每一个节点*/
int data;//数据
struct node *next;//指向下一个位置的指针
}node;
node* create/*创建*/(int n){ //指针类型的函数 ,所传的值n是总人数
node *p = NULL, *head; //用结构体指针声明一个临时的中间指针,指向当前节点 p是经常需要换人的
head = (node*)malloc(sizeof (node )); //为头结点分配内存空间;;;创建一个头结
p = head; //头结点指向中间节点
node *s;
int i = 1; //声明变量i,作为当前的元素位置记录
if( 0 != n){ /**每次都会kill 一个人,所以(0 != n )就是说还有人活着 ,就继续*/
// 前面那句说错了,应该是如果传经来的人数不为零,就开始工作
while(i <= n){ //如果当前标记位置小于总人数 ,每次循环,都会i++ ,共执行41此
s = (node*)malloc(sizeof(node));//动态的分配存储空间 ,s和p是一样的,都是临时的
s->data = i++; //将s节点对应的数据赋值给i,之后i再++
//其实就是为了循环链表初始化,第一个节点为1,第二个节点为2
p->next = s; //p是从头结点开始的,而s是从1号位置开始的,,
// 这一行和下面一行是联合起来看的,头不是1,而是0位置,所以p总是比s慢一拍,所以才会有 一个指一个,一个指一个 的效果。
p = s;
}
s->next = head->next; //这一切都结束之后,尾部指向第一个节点,而不是头节点
}
free(head); //此时尾指针已经指向第一个节点了,所以就不需要头指针了,于是释放掉。
return s->next; //++++++++++++++返回值是一个指针,指向链表第一个节点的指针
//s此时又是作为尾而指向第一个节点的,所以返回的就是第一个结点的地址
}
int main()
{
int n = 41; //确定人数
int m = 3; //每次间断的人数
int i; //控制变量,不用管,后面加上的
node *p = create( n); //++++++++++++++返回值是一个指针,指向链表第一个节点的指针 ,改地址存放在p这个指针里面
node *temp; //声明临时指针,##########################
m %= n; //这里是等于2;//这个取余数,就意味着总人数间隔三位下来,有两个人存活
while(p != p->next){ //自个指向自个,就是只剩下一个人了,就是一个空表了,就结束
for(i = 1;i < m-1; i++){ //链表开始,要适应从1开始数数,而不是0 ,
//m=2的话,该循环就执行一次,
p = p->next; //p当前指向第一个节点,p->next就是指向第二个节点了,再将第二个节点赋值给p,作为当前的地址
}
printf("%d-->",p->next->data); //输出p节点指针域指向的数据 p当前是第二个地址,那么输出端的p->next就是第三个人了p->next->data就是这个人的号码
//开始删除节点了
temp = p->next; //删除第m个节点
p->next = temp->next ;
free(temp);
p = p->next;
}
printf("%d\n",p->data); //打印最后判定的人是谁
return 0;
}