双向循环链表实现约瑟夫环

      今天,我们来讲讲双向循环链表约瑟夫环,小编解读的摇摆约瑟夫环的原理:输入一定人数的同学,成环排列,每个人携带一个密码,给出一个上限值,指针从第一个同学走到第上限值个同学,这个同学出队,且把它携带的密码存起来,指针走向她的下一个同学,又向前找到第上限值个同学,这个同学出队并存入她的密码值,指针指向他的前一个,之后又重复上面步骤,直到所有同学出队,密码完全生成。原理如上那么我们该如何实现呢?

      首先,在实现约瑟夫环前我们需要实现双向循环链表,实现双向循环链表先实现双向链表,在它的基础上添加一个实现循环函数。那么如何实现一个双向链表呢?我们可以紧紧抓住它的名字:双向、链表,我们需要构造出这两个东西,链表由一个个节点,双向-两个指针即此节点的前继(存前一个节点地址)和后驱(存后一个节点地址),为了实现约瑟夫环,节点里还需要有序列号和每个人所携带的密码值即数据域。这样我们就建好了一个节点的架子,实现链表,无非就是这样的很多节点串起来,像链条一样,由于是双向链表,我们可以在任意节点处向前或向后找到目标节点,这也弥补了单向链表的不足。

      之后我们需要考虑,它需要实现的一些功能。链表既然是一种存储结构与数据紧密相连,为数据而生,那么它的基本功能肯定与数据脱不了干系,对数据的操作增、删、改、查。最后由于是个循环链表,功能函数里也包含循环构成函数,形成约瑟夫环取出密码又需要得知环中人数和上限值,最后还要把取出密码打印出。此处又涉及到获得人数的函数、输入上限值的函数、得到密码的函数。总的来说所有函数包括增函数、删函数、改函数、查函数、求链表长度函数、这些函数声明和节点定义写在头文件中方便使用。如图:

      接下来,我们会详细说一下部分主要函数,首先,是增函数即插入函数(这里我们用的尾插),其传入参数为环中总人数。尾插函数作用就是产生节点并且链接节点,尾插逻辑:产生节点我们声明并使用指针变量并用malloc为它分配内存,输入序列号和携带的一个密码值,在声明一个指针front指向它,防止它被篡改。之后使用for循环创建总人数减一个节点并链接,front的下一个地址指向新插入这个指针变量,并且把这个指针变量的后一个指向置为空(防止后面野指针访问),把front指针移向这个新指针变量,尾插逻辑就是这样。如图:

     循环函数,其逻辑就是找到尾节点,把尾节点的next改为指向头结点,把头结点的前继指针指向尾节点。如图:

      求链表长度函数较好的方法是使用do-while()函数,int len=0;在头指针不会空的情况下,新建一个指针front指向头指针所指,防止改变和破坏头指针,在do-while()中len++,且front指针后移,循环停止条件是front==head,在第一次执行到此处时,front早已指向第一个节点的下一个。如图:

      取密码函数,也是解决这个问题的最关键的一个部分之一,实现原理的关键。先判断表是否为空,之后依然新声明一个cur3指针变量指向第一个节点,作用跟前面一样。因为这个指针需要顺时针走后逆时针走,那么电脑什么时候知道往哪里走呢,这就需要做个标记,int p=0;存入数组时需要知道是哪个下标,所以int k=0;保证队里人数都走完需要循环,又为了不轻易改动传入的总人数值,创建一个与他同值的变量j利用while循环。循环里由p值决定走顺还是逆,顺的话,利用for循环cur3后移上限值减一步(因为指针本身在第一个节点)走到第上限值个节点,退出循环,存下此节点的密码值,且下标++,之后找到此节点的前一个节点,把此节点的next赋给前一个节点,且此节点的next节点的前继指向此节点的前一个节点,把此节点的前继和后驱置空,此节点的指针cur3又把它指向它原来的下一个节点修改p=1;为了下次逆时针执行,走了一个人,j--。下一次执行p不为0执行else语句。也就是逆时针移动,利用for循环cur3前移上限值减一步(因为指针本身在第一个节点)走到第上限值个节点,退出循环,存下此节点的密码值,且下标++,找到cur3的后一个节点,把后一个节点的前继改为cur3的前继,又把cur3的前继的后驱改为cur3 的后继,cur3的前继和后驱置空,移动cur3指针指向cur3 的原来的前一个节点,修改标记p=0,人数 j--。如此往复直到人走完。如图: 

      以上就是小编对双向循环链表实现约瑟夫环的理解,若有错,麻烦您指出,小编很想进步!感谢!!(以上代码块不完全哦!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值