循环链表的经典问题

来源:互联网 发布:知乎周刊 epub 编辑:程序博客网 时间:2024/06/12 21:56

在罗马人占领桥塔帕特之后,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;}
原创粉丝点击