单向环形链表介绍
单向环形链表可以理解为单链表首尾相连的链表.
创建环形链表
- 构建一个单向环形链表思路
- 先创建第一个节点,让first指向该节点,并形成环形 first.next = first
- 添加辅助指针curBoy = first 待添加的节点为boy
- 添加节点 curBoy.next = boy;boy.next = first;(成环) curBoy = boy;(指向下一个节点)
- 遍历
- 先让一个辅助针织curBoy指向first节点
- 然后通过while循环遍历该环形链表即可,结束条件为:curBoy.next == first
josephu问题
设编号为1,2,3......n的n个人围坐一圈,约定编号为k(1<=k<=n)的人从1开始报数,数到m的那个人出列,他的下一位从1开始报数,数到m的那个人又出列,以此类推,知道所有人出列为止,由此产生一个出队编号的序列.
-
提示:用一个不带头结点的循环链表来处理josephu问题:先构建一个有n和节点的单循环链表,然后由k节点起从1开始计数,计数到m,对应节点从链表中删除,然后被删除的下一个节点又从1开始计数,知道最后一个节点从链表中删除.
-
需要创建一个辅助指针helper,事先应该指向环形链表的最后一个节点 (遍历实现 结束条件 helper.next = first)
-
报数前,先让first和helper移动k-1次 (这是题中的从第k个人开始报数)
-
当小孩报数时,让first和helper指针同时移动m-1次
-
这时就将first指向的小孩出圈.
- first = first.next;
- helper.next = first
代码实现
public class circleLinkedList {
public static void main(String[] args) {
CircleLinked circleLinked = new CircleLinked();
// 测试添加
circleLinked.add(5);
circleLinked.list();
System.out.println("测试出圈----------------");
//测试出圈
circleLinked.countBoy(5,1,2);
}
}
//循环链表
class CircleLinked{
//第一个节点 设置为null 是因为下面会进行复制
private Boy first = null;
/**
*
* @param num 向环形链表添加的节点数目
*/
public void add(int num){
if (num < 1){
System.out.println("输入无效数据!!");
return;
}
Boy curBoy = null; // 添加辅助指针
for (int i = 1;i <= num;i++){
Boy boy = new Boy(i);
//第一个节点
if (first == null){
first = boy;
first.setNext(first);
curBoy = first; //让辅助指针指向first
}else {
curBoy.setNext(boy);
boy.setNext(first); //尾节点指向头结点,成环
curBoy = boy; //指向下一个节点
}
}
}
//显示链表
public void list(){
if (first == null){
System.out.println("链表为空!!");
return;
}
Boy curBoy = first;
while (true){
System.out.printf("小孩编号为%d
",curBoy.getNo());
if (curBoy.getNext() == first){
break;
}
curBoy = curBoy.getNext();
}
}
/**
*
* @param n 总共有多少和小孩
* @param k 从第几个人开始报数
* @param m 数几下
*/
public void countBoy(int n,int k,int m){
//校验数据
if (first == null || k < 1 || k > n){
System.out.println("数据有误");
return;
}
Boy helper = first;
//helper指向环形链表的最后一个节点
while (true){
if (helper.getNext() == first){
break;
}
helper = helper.getNext();
}
///小孩报数前,先让 first 和 helper 移动 k - 1 次
for (int i = 0;i < k-1;i++){
first = first.getNext();
helper = helper.getNext();
}
while (true){
if (helper == first){ //圈中只有一个节点
break;
}
//first 和 helper 移动m-1此
for (int i = 0;i < m-1;i++){
first = first.getNext();
helper = helper.getNext();
}
//出圈小孩
System.out.printf("出圈编号为%d
",first.getNo());
first = first.getNext();
helper.setNext(first);
}
System.out.printf("出圈编号为%d
",first.getNo());
}
}
class Boy{
private int no;
private Boy next;
public Boy(int no){
this.no = no;
}
public int getNo() {
return no;
}
public Boy getNext() {
return next;
}
public void setNext(Boy next) {
this.next = next;
}
}