11、java环形单链表解决约瑟夫问题
环形单向链表:守卫连接的一个单向链表,每个节点中有其变量和一个指针指向下一个节点。头节点可有可无,此处写的没有头节点。
创建,先创建一个没有数据的first节点表示整个链表的第一个节点
添加,此处的添加与之前的不同,这里的每个节点比较简单且无顺序可言,可直接生成环形链表而非和之前一样一个个添加。所以此处传入函数的参数为节点个数,用for循环生成循环单链表。其中生成第一个节点时需要把first节点的数据替换掉,因此在i=1的时候需要额外判断一步将生成的新节点替换掉first中的无数据。并将next连到自己身上,并将temp赋值first。其他的节点只需生成新节点后将其赋值给temp的next并将新节点的next连到第一个节点即可,最后也要将temp后移、
public void add(int n){ if(n<2){ System.out.println("人数太少"); return; } Boy temp=null; for (int i=1;i<=n;i++){ Boy boy=new Boy(i); if(i==1){ first=boy; first.next=first; temp=first; }else { temp.next=boy; boy.next=first; temp=temp.next; } } }
遍历,判断链表不为空后利用辅助节点等于first开始不断后移遍历,辅助节点为最后一个时结束遍历
其中,辅助节点temp.next=first时temp为最后一个节点,first,next=null时链表为空
public void list(){ if(first.next==null){ System.out.println("链表为空"); } Boy temp=first; while (true){ System.out.println(temp.no); if(temp.next==first) break; temp=temp.next; } }
Josephu(约瑟夫、约瑟夫环)问题
Josephu问题为: 设编号为1,2,.. n的n个人围坐一-圈,约定编号为k (1<=k<=n)的人从1开始报数,数到m的那个人出列,它的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列。
思路:设置一个helper变量,指向first的后一个即链表的最后一个节点。helper节点用while函数使其指向链表中的最后一个节点,即当其next为first时它为最后一个节点。
因为要从编号n开始数,数k下,所以这个函数需要的参数有startno(开始报数的编号)、countnum(报的数字)、nums(总的节点数)
需要在最开始检查几个变量的合理性,我自己写的时候虽然不影响整体结果但漏考虑了几种条件。老师此处的判断有如下几个:链表为空,开始编号小于1,开始编号大于总数
先将helper和first共同后移countnum-1个,让first到达开始报数的位置,接下来的程序都是重复的程序,不断找出一个个节点将其踢出链表。所以此处用一个while函数编写,其中包含了几个步骤:
1、设置跳出函数的判断条件,当链表中只剩一个节点时,跳出while循环,即first=helper时跳出循环。
2、以for循环不断报数,让helper和first后移countnum个,此时first指的节点便为要踢出链表的节点。这里我们让first再往后移一次,则现在要删除的节点位于helper和first之间,此时让first与helper连起来即可。
代码如下:
public void count(int startNo,int countNum,int nums){ if(nums<1||nums<startNo||first==null||startNo<1){ System.out.println("数据输入有误"); return; } Boy helper=first; while (true){ if(helper.next==first) break; helper=helper.next; } for (int i=0;i<startNo-1;i++){ helper=helper.next; first=first.next; } while(true){ if(first==helper){ break; } for (int i=0;i<countNum-1;i++){ helper=helper.next; first=first.next; } System.out.println(helper.next.no); first=first.next; helper.next=first; } System.out.println(first.no); }
其实这个问题并不难,用数组等方法也可以轻松做出来。但以此方法一个是了解了链表中的环形链表的结构和创建方式,另一个也是学到了其的应用。