约瑟夫环问题学习笔记(韩顺平老师版)

约瑟夫问题

约瑟夫问题又称丢手绢问题,一群小孩围成一圈,从第m个小孩开始数数,数到第n个小孩出列,剩下的小孩继续数数,直到剩最后一个小孩考常知识<单向环形链表>

public class Josephu {
    
    
    public static void main(String[] args) {
    
    
        //测试
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.addBoy(5);//加入5个小孩
        circleSingleLinkedList.showBoy();

        circleSingleLinkedList.countBoy(1,2,5);
    }
}
//创建环形单向链表
class CircleSingleLinkedList{
    
    
    private Boy first = null;
    //添加小孩节点,创建环形链表
    public void addBoy(int nums){
    
    
        //nums数据判断
        if(nums<1){
    
    
            System.out.println("nums的值不正确");
            return;
        }
        Boy curBoy = null; //辅助指针,帮助构建环形链表
    //使用for循环创建环形链表
    for(int i=1;i<=nums;i++){
    
    
        //根据编号,创建小孩节点
        Boy boy = new Boy(i);
        if(i ==1){
    
    
            first = boy;
            first.setNext(first);//构成环状
            curBoy = first;//让curBoy指向第一个小孩
        } else {
    
    
            curBoy.setNext(boy);
            boy.setNext(first);
            curBoy = boy;
        }
    }
}
//遍历环形链表
public void  showBoy(){
    
    
    if(first == null){
    
    
        System.out.println("链表为空");
    }
    //因为first不能动,因此我们需要一个辅助指针
    Boy curBoy = first;
    while (true){
    
    
        System.out.printf("小孩的编号为 %d \n",curBoy.getNo());
        if(curBoy.getNext() == first){
    
    
            break;//遍历完毕
        }
        curBoy=curBoy.getNext();//curBoy后移
    }
}

//根据用户输入,计算出圈顺序

/**
 *
 * @param StartNo  表示从第几个小孩开始数数
 * @param countNum  表示数几下
 * @param nums  表示小孩总数
 */
public void countBoy(int StartNo,int countNum,int nums){
    
    
    //数据校验
    if(first ==null || StartNo<1 || StartNo>nums){
    
    
        System.out.println("数据输入有误,请重新输入");
        return;
    }
    //创建一个辅助指针,帮助小孩出圈
Boy helper = first;
while (true){
    
    
    if(helper.getNext() == first){
    
    //说明helper指向了最后一个节点
        break;
    }
    helper = helper.getNext();
}
//先让first和helper移动到报数的那个小孩位置,移动k-1次
for(int j=0;j<StartNo -1;j++){
    
    
    first = first.getNext();
    helper = helper.getNext();
}
//当小孩报数,first和helper移动m-1次,然后出圈
        while (true){
    
    
            if(first == helper){
    
    //说明圈中只有一个人
                break;
            }
            for (int j=0;j<countNum-1;j++){
    
    
                first = first.getNext();
                helper = helper.getNext();
            }
            //此时first指向的小孩出圈
            System.out.printf("小孩%d出圈\n",first.getNo());
            //出圈
            first = first.getNext();
            helper.setNext(first);
        }
        System.out.printf("最后留在圈的小孩%d \n",first.getNo());
    }
}
//创建一个boy类,表示一个节点
class Boy{
    
    
    private int no;//编号
    private Boy next;//指向下一个节点,默认null

    public  Boy(int no){
    
    
        this.no = no;
    }

    public int getNo() {
    
    
        return no;
    }

    public void setNo(int no) {
    
    
        this.no = no;
    }

    public Boy getNext() {
    
    
        return next;
    }

    public void setNext(Boy next) {
    
    
        this.next = next;
    }
}

猜你喜欢

转载自blog.csdn.net/zjdzka/article/details/109755880