线性表_循环链表(增减删查 + 约瑟夫环问题 代码实现 )

来源:互联网 发布:壁虎数据恢复官网 编辑:程序博客网 时间:2024/06/06 00:41

1.概念

循环链表是链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。

判断空链表的条件是

head==head->next;

rear==rear->next;

循环链表的特点是无须增加存储量,仅对表的链接方式稍作改变,即可使得表处理更加方便灵活。①循环链表中没有NULL指针。涉及遍历操作时,其终止条件就不再是像非循环链表那样判别p或p->next是否为空,而是判别它们是否等于某一指定指针,如头指针或尾指针等。 ②在单链表中,从一已知结点出发,只能访问到该结点及其后续结点,无法找到该结点之前的其它结点。而在单循环链表中,从任一结点出发都可访问到表中所有结点,这一优点使某些运算在单循环链表上易于实现。

约瑟夫环问题由来:

据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。
17世纪的法国数学家加斯帕在《数目的游戏问题》中讲了这样一个故事:15个教徒和15 个非教徒在深海上遇险,必须将一半的人投入海中,其余的人才能幸免于难,于是想了一个办法:30个人围成一圆圈,从第一个人开始依次报数,每数到第九个人就将他扔入大海,如此循环进行直到仅余15个人为止。问怎样排法,才能使每次投入大海的都是非教徒。
代码实现为第m个人(如m=3)

2.代码

//循环链表(circular linked list)的实现  增减删查#include <stdio.h>#include <stdlib.h>/*链表存储结构的定义*/typedef struct CLinkList{int data;struct CLinkList *next; //指向下一个链表元素的指针}node;/*****************************************************//*                   对循环链表的操作                 *//*****************************************************//*函数作用:初始化循环链表*//*参    数:pNode-循环链表第一个结点*/void ds_init(node **pNode){int item;             //存储输入内容node *temp;           //临时存储的结点指针node *target;         //用于动态查找的结点指针printf("请输入结点的值,输入0完成初始化 \n");while (1){scanf("%d", &item); //将输入内容存入变量item对应的地址中fflush(stdin);      //清空缓存区if (item == 0){return;}if ((*pNode) == NULL)  //循环链表中 插入第一个结点{*pNode = (node*)malloc(sizeof(struct CLinkList)); //为结点分配内存地址if (!(*pNode))  exit(0);                    //分配地址失败为0,退出程序(*pNode)->data = item;                      //将第一个结点数据设成item(*pNode)->next = *pNode;      //链表仅有一个结点时,该结点的next指向自己}else{/*找到最后一个结点赋值给target 即next指向第一个结点的结点*/for (target = (*pNode); target->next != (*pNode); target = target->next);/*生成新的结点*/temp = (node*)malloc(sizeof(struct CLinkList));if (!temp)  exit(0);temp->data = item;temp->next = *pNode;target->next = temp;}}}/*函数作用:插入结点*//*参    数: pNode-链表第一个结点, i-插入位置*/void ds_insert(node **pNode, int i){node *temp;                 //临时存储新插入的结点指针node *target;               //用于动态查找的结点指针node *p;                    //存储要插入位置的原来的元素int item;int j = 1;                  //线性表起始下标为1printf("请输入要插入的结点的值  \n");scanf("%d", &item);         //将输入内容存入变量item对应的地址中if (i == 1)          //在第一个位置插入结点//      {temp = (node*)malloc(sizeof(struct CLinkList));if (!temp)  exit(0);temp->data = item;/*找到最后一个结点赋值给target 即next指向第一个结点的结点*/for (target = (*pNode); target->next != (*pNode); target = target->next);temp->next = (*pNode);      // 使插入结点指向 原来的头结点(变成了第二个元素)target->next = temp;        //将尾结点 指向 插入的结点*pNode = temp;              //设置新的头结点为 插入的结点}else{target = *pNode;            //将头结点赋给target    //i为插入的位置,获取要插入位置的的前一个结点,并赋给target    //如i=4,则j<3循环j=1,2 两次 指向第三个位置for (; j < (i - 1); j++){target = target->next;}temp = (node*)malloc(sizeof(struct CLinkList));if (!temp)  exit(0);temp->data = item;p = target->next;           //将要插入位置i原来的元素提取出来target->next = temp;        //将要插入的元素放到i的位置temp->next = p;             //将原来的元素 连接到 新插入的元素的后面}}/*函数作用:删除结点*//*参    数:pNode-链表第一个结点, i-删除位置*/void ds_delete(node **pNode, int i){node *target;node *temp;int j = 1;if (i == 1)  //删除第一个结点时{//找到最后一个结点for (target = *pNode; target->next != *pNode; target = target->next);temp = *pNode;             //提取出第一个结点*pNode = (*pNode)->next;   //将结点2赋给第一个结点target->next = *pNode;     //最后一个结点指向 新的第一个结点(原结点2)free(temp);                //释放原来的第一个结点内存空间}else{target = *pNode;            //将头结点赋给targetfor (; j < (i - 1); j++)    //获取要删除的结点的前一个结点{target = target->next;}temp = target->next;        //提取要删除的结点itarget->next = temp->next;   //要删除结点i的前一结点的next 指向 要删除结点i的后一结点free(temp);}}/*函数作用:返回结点所在位置 int*//*参    数:pNode-链表第一个结点地址, elem-查找位置*/int ds_search(node  *pNode, int elem){node *target;int i = 1;//直到查找到要删除元素,或链表结尾为止,将查找到的结点赋给target ,此时i加到该结点对应位置for (target = pNode; target->data != elem && target->next != pNode; i++){target = target->next;}if (target->next == pNode)          //若到链表结尾未找到元素return 0;elsereturn i;}/*函数作用:遍历显示链表中元素*//*参    数:pNode-链表第一个结点地址 */void ds_traverse(node *pNode){node *temp;temp = pNode;printf("********************链表中元素如下*********************\n");do{printf("%4d ", temp->data);} while ((temp = temp->next) != pNode);printf("\n");}int main(){node *pHead = NULL;char opp = 'A';                  //记录操作字符int find;                  //记录结点位置printf("1.初始化链表 \n\n2.插入结点 \n\n3.删除结点 \n\n4.返回结点位置 \n\n5.遍历链表 \n\n请选择你的操作\n");while (opp != '0'){scanf("%c", &opp);switch (opp){case '1':ds_init(&pHead);printf("\n");ds_traverse(pHead);break;case '2':printf("输入要插入结点的位置?");scanf("%d", &find);ds_insert(&pHead, find);printf("在位置%d插入值后:\n", find);ds_traverse(pHead);printf("\n");break;case '3':printf("输入要删除的结点的位置?");scanf("%d", &find);ds_delete(&pHead, find);printf("删除第%d个结点后:\n", find);ds_traverse(pHead);printf("\n");break;case '4':printf("你要查找数值为多少的结点的位置?");scanf("%d", &find);printf("元素%d所在位置:%d\n", find, ds_search(pHead, find));printf("\n");break;case '5':ds_traverse(pHead);printf("\n");break;case '0':exit(0);}}return 0;}
/** JosephProblem * 41个人一群人围坐成一圈,从1号开始,每三人个去除一个人,然后以原去除的人后面的那个人为第一个,每三个人去除一个人,知道所有人全部去除 求去除编号顺序*/#include <stdio.h>#include <stdlib.h>/*链表存储结构的定义*/typedef struct node{int data;struct node *next; //指向下一个链表元素的指针}node;/*初始化循环链表*/node *create(int n){node *p = NULL;    //临时结点,作为指针使用node *head;        //头结点,作为开始索引head = (node*)malloc(sizeof(node));p = head;          //指向头结点node *s = NULL;    //作为当前结点int i = 1;         //循环链表开始索引if (0 != n)        //创建元素个数不为0{while (i <= n)                //依次创建各结点{s = (node*)malloc(sizeof(node));s->data = i++;          //i结点值为ip->next = s;            //指向下一节点p = s;                  //当前结点赋给指针P}s->next = head->next;         //尾结点指向第一个结点free(head);return  s->next;}}int main(){int n = 41;          //环总数int m = 3;           //步长int i;node *p = create(n); //创建循环链表 node *temp;m %= n;              //设定步长使用while (p != p->next) //未删除到空链表时{for (i = 1; i < m - 1; i++){p = p->next;      //若步长为m=3,循环1次,执行for后p指向结点2,输出结点3的值}printf("%d->", p->next->data);temp = p->next;         //提取要去除的结点(p是node2 temp是node3)p->next = temp->next;   //删除结点的前一结点指向删除结点的后一结点free(temp);p = p->next;            //原删除结点的后一结点重新作为第一个结点进行下一轮循环}printf("%d\n", p->data);       //输出最后结点return 0;}



3.结果



0 0
原创粉丝点击