算法与数据结构

单向链表解决约瑟夫问题

2020-02-05  本文已影响0人  shengjk1

1.什么是约瑟夫问题?


image

2.约瑟夫问题的解决方式
通过单向循环链表解决,具体思路如下:

/**
 * @author shengjk1
 * @date 2020-02-06
 */

public class Josephus {
    public static void main(String[] args) {
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.addBoys(5);
        circleSingleLinkedList.show();
//      circleSingleLinkedList.countBoy(5);
        circleSingleLinkedList.countBoy(1, 2, 5);
    }
}

//先创建一个 单向循环列表类
class CircleSingleLinkedList {
    private Boy first = null;
    private Boy firstPre = null;
    private int nums;
    
    //设置这个列表中添加多少个小孩
    public void addBoys(int nums) {
        if (nums < 1) {
            System.out.println("nums 值不正确 !");
            return;
        }
        this.nums = nums;
        Boy curBoy = null;
        for (int i = 1; i <= nums; i++) {
            if (i == 1) {
                first = new Boy(i);
                first.setNext(first);
                curBoy = first;
            } else {
                Boy boy = new Boy(i);
                curBoy.setNext(boy);
                curBoy = boy;
                curBoy.setNext(first);
            }
            firstPre = curBoy;
        }
    }
    
        /*
        1.创建一个辅助指针 helper,事先应该指向环形链表的最后一个节点
        2.当小孩报数时,让 first 和 helper 指针同时移动 m-1 次
        3.这时就可以将 first 指向的小孩节点出圈
        first=first.next
        helper.next=first
         */
    
    //偷懒的方式,借助 firstPre(helper),简易版的,或者直接通过循环找到 firstPre(helper)
    public void countBoy(int m) {
        while (true) {
            for (int i = 1; i < m; i++) {
                first = first.getNext();
                firstPre = firstPre.getNext();
            }
            System.out.println("移除 " + first.getNo());
            first = first.getNext();
            firstPre.setNext(first);
            if (firstPre == first) {
                System.out.println("移除 " + first.getNo());
                break;
            }
        }
    }
    
    
    /**
     * 复杂版,逻辑与简易版类似
     *
     * @param startNo  表示从第几个小孩开始数数
     * @param countNum 表示数几下
     * @param nums     表示最初有多少个小孩在权重
     */
    public void countBoy(int startNo, int countNum, int nums) {
        if (first == null || startNo < 1 || startNo > this.nums || nums > this.nums) {
            System.out.println("参数有误,请重新输入!");
            return;
        }
        Boy helper = first;
        while (true) {
            //直接移动到 startNo
            if (helper.getNext().getNo() == startNo) {
                break;
            }
            helper = helper.getNext();
        }
        first = helper.getNext();
        
        while (true) {
            if (helper == first) {
                System.out.println("最后留在圈中的小孩是 " + first.getNo());
                break;
            }
            
            for (int i = 1; i < countNum; i++) {
                first = first.getNext();
                helper = helper.getNext();
            }
            System.out.println("移除小孩 " + first.getNo());
            first = first.getNext();
            helper.setNext(first);
        }
    }
    
    //展示所有的小孩编号
    public void show() {
        if (first == null) {
            System.out.println("单向循环链表表为 null");
            return;
        } else {
            Boy curBoy = first;
            while (true) {
                System.out.println("boy num " + curBoy.getNo());
                curBoy = curBoy.getNext();
                if (curBoy == first) {
                    break;
                }
            }
        }
    }
}

class Boy {
    private int no;
    private Boy next;
    
    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;
    }
}

3.单向循环链表的使用场景

4.关于单向循环链表的面试题

上一篇下一篇

猜你喜欢

热点阅读