数据结构(五)-环形链表及约瑟夫问题
一、单向环形链表的应用场景(约瑟夫问题)
Josephu 问题为:设编号为1,2, ... n 的 n 个人坐成一圈,约定从编号为 k(n≥k≥1) 的人开始报数,数到 m 的那个人出列,她的下一位又从 1 开始报数,数到 m 的那个人又出列,以此类推,直到所有人出圈为止,因此形成一个出圈编号的序列
二、单向链表的示意图
三、创建环形链表图解
创建环形链表代码实现
// 创建单向环形链表
class SingleCircularLinkedList{
// 初始化一个头节点
Girl first = null;
// 添加数据到链表中
public void add(int num) {
// 校验参数
if(num < 1) {
System.out.println("您输入的小孩个数小于1,不能创建环形链表");
}
// 定义临时指针
Girl curGirl = first;
for(int i = 1; i <= num; i++) {
Girl girl = new Girl(i);
if(i == 1) { // 说明是第一个节点
first = girl;
first.setNext(first);
curGirl = first;
}else {
curGirl.setNext(girl);
curGirl = girl; // curGirl 后移
curGirl.setNext(first); // 形成闭环
}
}
}
// 遍历链表
public void list() {
// 判断链表是否为空
if(first == null) {
System.out.println("当前链表为空");
return;
}
// 定义临时指针
Girl curGirl = first;
while(true) {
System.out.printf("小孩编号为 %d \n", curGirl.getNo());
if(curGirl.getNext() == first) {
break;
}
curGirl = curGirl.getNext();
}
}
}
// 创建节点类
class Girl {
private int no;
private Girl next;
public Girl(int no) {
super();
this.no = no;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public Girl getNext() {
return next;
}
public void setNext(Girl next) {
this.next = next;
}
}
四、约瑟夫问题图解
补充,设置 helper 节点的思路来源于单向链表删除节点时,指针始终指在当前节点的前一位,cur.next = cur.next.next
代码实现
// 约瑟夫问题
public void joseph(int startNo, int countNum, int nums) {
// 参数校验
if(startNo < 1 || countNum > nums || nums < 1) {
System.out.println("输入的参数有误");
return;
}
// 定义临时指针
Girl helper = first;
// 让helper移动到first的上一个节点的位置,让first指针移动到startNo处(移动startNo - 1次)
while(true) {
if(helper.getNext() == first) {
break;
}
helper = helper.getNext();
}
for(int i = 0; i < startNo - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
// 让first和helper同时移动countNum - 1次,小孩出圈
while(true) {
if(helper == first) { // 条件成立说明圈中只有一个小孩
break;
}
for(int i = 0; i < countNum - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
// 小孩出圈操作
System.out.printf("出圈的小孩为 %d 号\n", first.getNo());
first = first.getNext();
helper.setNext(first);
}
// 输出圈中留下的lucky girl
System.out.printf("留在圈中的 lucky girl 为 %d 号\n", first.getNo());
}