环形链表概述
循环链表是另一种形式的链式存储结构。它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环。
环形链表的简单实现
节点的设计:
和普通的单链表一样
链表的功能实现类:
这里仅简单的实现一个环形链表,add方法接受一个整形的参数,用于设置链表有几个节点,用for循环,依次创建节点,节点名称固定,标号按照从1到整形参数k来设置
在每次创建新节点后,将其加入链表,如果链表中没有数据,则,将第一个节点设置为第一个结点,即first,并令first指向自己,当链表中有数据,则插入到第一个节点和倒数第一个节点的中间,并更新辅助接点temp,使其指向被插入的节点
链表遍历:
首先令temp指向first,然后进行遍历,遍历结束的判决条件是temp==first
约瑟夫问题的解决
此方法接收两个参数,一个代表从第几个学生开始报数,一个代表每一次的报数需要报到几
整体的思路是:首先为了方便出列,通过遍历,将temp指向倒数第一个节点,在遍历的过程中顺便统计一下共有多少人,然后此时temp指向了倒数第一个节点,并得到了共多少个学生,此时先判断传入的参数是否正确。正确后,根据要从第几个学生开始报数来把temp和first移动对应的次数,然后根据每次报几下来进行遍历出列,链表中仅剩一个人的判决条件是temp==first
// 约瑟夫问题的解决
// m:从第几个学生开始报数 k:每一次需要报几下
public void JosephuDemo(int m,int k){
if (first==null){
System.out.println("无数据");
return;
}
// 初始化temp
temp=first;
int n=1; //n表示共有多少学生
while (temp.next!=first){
//首先通过遍历使temp指向环链表"尾",即first的上一个节点。此举是为了方便移除学生
// 在遍历的时候顺便用n统计一下共有多少学生
// 注意n的初始值需要是1,因为这里while循环的次数仅仅是一个移动的次数,并不是节点的个数
// 就好比是线段,有头和尾两个点,但是从头到尾只需要移动一次
n++;
temp=temp.next;
}
// 得到n后,判断数据输入是否正确
if (m>n||m<1||k<1){
System.out.println("数据出错");
return;
}
// m表示从第几个学生开始数,所以在开始前,需要先将temp和first移动几次进行初始化
// 为什么是m-1?和前面n那里一样,此处m表示的是"个数",是从第几个学生开始数,这里for循环的次数仅仅是一个移动的次数
for (int i = 0; i < m-1; i++) {
// 移动
temp=temp.next;
first=first.next;
}
int p=1; //用于记录出列的学生是第几次出列
while (temp!=first){
//环链表中只剩一个学生的判别条件是temp==first,因为当链中数据大于1个时,temp和first一定是相邻的,并不是相同的
for (int i = 0; i < k-1; i++) {
// 为什么是k-1?和前面m同理,k表示的是"个数",这里for循环需要表示的是一个移动的次数
temp=temp.next;
first=first.next;
}
System.out.println("第"+p+"个出列的是"+first);
first=first.next; //找到后,将first节点跳到要出列节点的下一个节点,方便后续的遍历出列和判断
temp.next=first; //此处执行前,temp和first中间相隔一个节点,,此节点就是出列的节点,删除此节点,
p++; //更新p值
}
System.out.println("幸存者是"+first);
}