描述
方法
用一个不带头节点的循环链表处理Josephu问题:先构成一个有n个节点的单循环链表,然后由k节点起从1开始计数,计到m时,对应节点从链表中删除,然后再从被删除节点的下一个节点又从1开始计数,直到最后一个节点从链表中删除,算法结束
创建环形链表
添加节点
先创建一个节点,让first指向该节点,并形成环形
后面没创建一个新节点,就把该节点加入到已有的环形链表中即可
//创建first节点,当前没有编号
private JosephuNode first = null;
//添加节点,构建一个环形链表
public void add(int num){
//num校验
if(num < 1){
System.out.println("num值有误");
return;
}
JosephuNode cur = null; //辅助指针,帮助构建环形链表
//for循环创建环形链表
for (int i = 1; i <= num; i++) {
//根据编号创建节点
JosephuNode josephuNode = new JosephuNode(i);
//如果是第一个节点
if (i == 1) {
first = josephuNode; //josephuNode1的地址赋给first
first.setNext(first); //next的地址指向自己
cur = first; //first的地址赋给cur
} else {
cur.setNext(josephuNode); //josephuNode的地址赋给cur.next(cur和first的地址一样)
josephuNode.setNext(first); //josephuNode.next的地址指向first
cur = josephuNode; //cur后移(first地址不变),生成环形
}
}
}
遍历节点
辅助指针cur指向first节点
while循环至cur.next = first结束
//遍历环形链表
public void show(){
if(first == null){
System.out.println("链表为空");
return;
}
//first不能动,使用辅助指针遍历
JosephuNode cur = first;
while(true){
System.out.println(cur);
if(cur.getNext() == first) //遍历完毕
break;
cur = cur.getNext();
}
}
使用环状链表解决约瑟夫问题
/**
* 约瑟夫问题
* @param startNo 表示从第几个节点开始数
* @param count 表示数几下
* @param num 表示最初链表中有几个节点(也许不需要此参数)
*/
public void count(int startNo, int count, int num){
if(first == null || startNo < 1 || startNo > num){
System.out.println("参数有误");
return;
}
//创建一个辅助指针helper,指向环形链表最后的节点
JosephuNode helper = first;
while (helper.getNext() != first){
helper = helper.getNext();
}
//报数前先让first和helper移动k-1步到开始位置
for (int i = 0; i < startNo - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//报数时让first和helper移动m-1步,然后进行出圈操作
while (helper != first){ //链表中只有一个节点时结束循环
//first和helper同时移动count-1步
for (int i = 0; i < count - 1; i++) {
first = first.getNext();
helper = helper.getNext();
}
//此时first指向的节点就是要出圈的节点
System.out.println(first);
//出圈操作
first = first.getNext(); //first后面的节点地址赋给first,成为新的first
helper.setNext(first); //helper指向新的first,形成环状
}
//最后留在圈中的节点
System.out.println(first);
}