数据结构与算法(Java版)_06_环形单链表与约瑟夫问题

约瑟夫环:假如有n(n≥1)个人手拉手围在一起,从m(1≤m≤n)个人开始报数,最后一下报数的人出列,则出列的人的左右两边的人手拉手构成一个新的环状。

依次类推,直到最后一个人出列。

思路分析:先创建一个环形单向链表。每次添加节点的时候,永远将最后一个节点的next指针指向头结点。

创建指针curIndex指向头结点,curIndexPre指针永远指向curIndex的前一个元素。数count下,则这两个指针分别移动count-1次。

出列问题:指针curIndex最后停留的节点出列,然后curIndex = curIndex.next,目的是移动该指针到重组环后的最后一次停留的位置。

代码实现:

package dataStructureAtShangGuiGu;

public class JosePhusDemo {

    public static void main(String[] args) throws InterruptedException {
        CircleSingleLinkedList circleSingleLinkedList = new CircleSingleLinkedList();
        circleSingleLinkedList.add(4);
        sop("初始环状链表");
        circleSingleLinkedList.list();
        
        sop("报两次数出列顺序为:");
        circleSingleLinkedList.outByCount(4,1,circleSingleLinkedList.size());
    }
    private static void sop(Object obj) {
        System.out.println(obj);
    }
}
class CircleSingleLinkedList{
    public Person first;
    public CircleSingleLinkedList() {
        this.first = new Person(-1,"");
    }
    public void add(int nums) { //生成一个环形单链表
        Person cur = this.first;
        if(nums<1) {
            return;
        }
        for(int i=1;i<=nums;i++) {
            if(i==1) {
                this.first = new Person(i,"编号为"+i+"的男孩");
                cur = this.first;
                continue;
            }
            cur.next = new Person(i,"编号为"+i+"的男孩");
            cur = cur.next;
            cur.next = this.first;
        }
        cur = this.first;
    }
    public void list() { //显示环形链表元素
        Person cur = this.first;
        if(cur.no==-1) {
            this.sop("[]");
            return;
        }
        do {
            this.sop(cur);
            cur = cur.next;
        } while(this.first!=cur);
    }
    public void outByCount(int count,int startIndex,int maxSize) throws InterruptedException { //根据count报数出列
        if(this.first==null||startIndex<1||startIndex>maxSize||count<1) {
            this.sop("参数有误!");
            return;
        }
        Person curIndex = this.first;
        Person curIndexPre = this.first;
        while(curIndexPre.next!=this.first) { //将curIndexPre指针初始化到最后一个元素位置
            curIndexPre = curIndexPre.next;
        };
        for(int i=1;i<=startIndex-1;i++) { //分别移动curIndexPre、curIndex指针
            curIndex = curIndex.next;
            curIndexPre = curIndexPre.next;
        }
        while(true){
            for(int i=1;i<=count-1;i++) { //分别移动curIndexPre、curIndex指针
                curIndex = curIndex.next;
                curIndexPre = curIndexPre.next;
            }
            this.sop(curIndex); //出列
            if(curIndexPre==curIndex) break;
            curIndex = curIndex.next;
            curIndexPre.next = curIndex;
            Thread.sleep(1);
            
        }
    }
    public int size() { //获取环形链表长度
        Person cur = this.first;
        int size = 0;
        if(cur.no==-1) return size;
        do {
            size++;
            cur = cur.next;
        } while(this.first!=cur);
        return size;
    }
    private void sop(Object obj) { //方便打印函数,正常显示方式
        System.out.println(obj);
    }
}
class Person{
    public int no;
    public String name;
    public Person next;
    public Person(int no,String name) {
        this.no = no;
        this.name = name;
    }
    public String toString() {
        return "[no="+this.no+",name="+this.name+"]";
    }
}

运行测试:

这里我定义了一个4个节点的单向环链表,从第一个节点开始数,每次数两下,出列编号顺序是 4 1 3 2 结果正确。

原文地址:https://www.cnblogs.com/wmskywm/p/15464366.html