[数据结构]-循环单向链表解决Josephu

问题描述

经典的约瑟夫环问题为,一群小孩子手拉手围成一圈,然后指定某个小孩从1开始报数,直到报到M的小孩子出圈,然后下一个位置的孩子继续从1开始报数。游戏结束为圈中只剩下一个孩子。

主要思路

可以考虑通过使用循环单向链表来模拟该游戏的整个过程,解决该问题。

创建结点类

结点类主要包括结点的编号 no 属性和 Next 指针域

//Node class
class Node{
    public int no;
    public Node next;  //next
    
    //constructor function
    public Node(int no){
        this.no = no;
    }
}

创建循环单向链表类

循环单向链表采用无头结点的单向链表构建方式,属性包括头结点,成员方法包括创建结点围成的圈,遍历圈中所有结点,模拟结点出圈

成员方法介绍

1、createCircle(): 通过设置圈中结点个数来创建圈,使用辅助指针指向链表的最后位置,每次加入结点时使用辅助指针来完成

public void createCircle(int totalNums){
        if(totalNums < 1){
            System.out.println("can create Circle.");
            return;
        }
        Node lastNode = null;  //helper node to record last node position.
        
        for(int i = 1; i <= totalNums; i++){
            Node curNode = new Node(i);
            //The first node.
            if(i == 1){
                first = curNode;
                first.next = first; 
                lastNode = first;
            }else{
                lastNode.next = curNode;
                curNode.next = first;
                lastNode = curNode;
            }
        }
    }

2、visitCircle(): 使用辅助指针,依次遍历整个链表,直到访问到最后位置的结点退出

public void visitCircle(){
        if(first == null){
            System.out.println("Circle is empty.");
            return;
        }
        Node tmpNode = first;
        while(true){
            System.out.println("curNode Number: " + tmpNode.no);
            if(tmpNode.next == first){
                break;
            }
            tmpNode = tmpNode.next;
        }
    }

3、outCircle(): 模拟出圈过程,首先定义辅助指针 lastNode 用于指向链表的最后位置辅助出圈,第一步将辅助指针移动到链表尾部位置,第二步将 first 指针和 lastNode 指针移动到报数的起始位置,第三步循环,然后将first 指针和 lastNode 指针移动报数步找到要出圈的结点,将其出圈,直到最终链表中只剩下一个结点为止

public void outCircle(int startNo, int countNum, int totalNums){
        if(first == null || startNo < 1 || startNo > totalNums){
            System.out.println("Can not start the game.");
            return;
        }
        Node lastNode = first; // record last node position.
        //1、首先将lastNode移动到当前链表的最后位置
        while(true){
            if(lastNode.next == first){
                break;
            }
            lastNode = lastNode.next;
        }
        //2、将first和辅助指针同时向后移动startNo-1位置到达开始报数的起始位置
        for(int i = 1; i < startNo; i++){
            first = first.next;
            lastNode = lastNode.next;
        }
        //3、将first和辅助指针同时向后移动countNum - 1位置,使当前位置结点出圈,使用循环直到圈中只还有一个结点
        while(true){
            // Only one node left in the circle.
            if(lastNode == first){
                break;
            }
            for(int i = 1; i < countNum; i++){
                first = first.next;
                lastNode = lastNode.next;
            }
            // delete curNode from circle.
            System.out.print(first.no + " -> ");
            first = first.next;
            lastNode.next = first;
        }
        System.out.print("LastNode:" + first.no);
    }

完整代码

import java.io.*;
import java.util.*;
//Author:Peiliang Gong
//DataStructure:[Josephu implemented by CircleSingleLinkedList]

//Node class
class Node{
    public int no;
    public Node next;  //next
    
    //constructor function
    public Node(int no){
        this.no = no;
    }
    
}

class CircleSingleLinkedList  
{   
    public Node first = null;
    
    public void createCircle(int totalNums){
        if(totalNums < 1){
            System.out.println("can create Circle.");
            return;
        }
        Node lastNode = null;  //helper node to record last node position.
        
        for(int i = 1; i <= totalNums; i++){
            Node curNode = new Node(i);
            //The first node.
            if(i == 1){
                first = curNode;
                first.next = first; 
                lastNode = first;
            }else{
                lastNode.next = curNode;
                curNode.next = first;
                lastNode = curNode;
            }
        }
    }
    
    public void visitCircle(){
        if(first == null){
            System.out.println("Circle is empty.");
            return;
        }
        Node tmpNode = first;
        while(true){
            System.out.println("curNode Number: " + tmpNode.no);
            if(tmpNode.next == first){
                break;
            }
            tmpNode = tmpNode.next;
        }
    }
    
    public void outCircle(int startNo, int countNum, int totalNums){
        if(first == null || startNo < 1 || startNo > totalNums){
            System.out.println("Can not start the game.");
            return;
        }
        Node lastNode = first; // record last node position.
        //1、首先将lastNode移动到当前链表的最后位置
        while(true){
            if(lastNode.next == first){
                break;
            }
            lastNode = lastNode.next;
        }
        //2、将first和辅助指针同时向后移动startNo-1位置到达开始报数的起始位置
        for(int i = 1; i < startNo; i++){
            first = first.next;
            lastNode = lastNode.next;
        }
        //3、将first和辅助指针同时向后移动countNum - 1位置,使当前位置结点出圈,使用循环直到圈中只还有一个结点
        while(true){
            // Only one node left in the circle.
            if(lastNode == first){
                break;
            }
            for(int i = 1; i < countNum; i++){
                first = first.next;
                lastNode = lastNode.next;
            }
            // delete curNode from circle.
            System.out.print(first.no + " -> ");
            first = first.next;
            lastNode.next = first;
        }
        System.out.print("LastNode:" + first.no);
    }
    
    //main function
	public static void main (String[] args) throws java.lang.Exception
	{
		CircleSingleLinkedList circle = new CircleSingleLinkedList();
		circle.createCircle(5);
		circle.visitCircle();
		
		circle.outCircle(1,2,5);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值