约瑟夫问题

1、问题描述

n个人围成一圈,从第k个人开始报数,报到m的人出圈,剩下的人继续从出圈的下一个人开始报数,报到m的人出圈;如此往复,直到所有人出圈。(模拟此过程,输出出圈的人的序号)。

 

2、采用单向循环链表实现

节点

public class HeroNode {

    protected Integer no;
    protected String name;
    protected HeroNode next;

    public HeroNode(Integer no, String name) {
        this.no = no;
        this.name = name;
    }

    @Override
    public String toString() {
        return "HeroNode[" +
                "no=" + no +
                ", name='" + name + '\'' +
                ']';
    }
}
View Code

 

单向循环链表:主要通过两个指针实现,first指针指向头节点,tail指向尾节点,再将tail的next指针指向first形成循环单向链表。

public class SingleCiruLinkedList {

    protected HeroNode first;
    protected HeroNode tail;

    /**
     * 添加元素,构成单向循环链表
     * @param hero
     */
    public void add(HeroNode hero) {
        if (first == null) {
            first = hero;
            tail = hero;
            first.next = first;
        } else {
            tail.next = hero;
            tail = hero;
            tail.next = first;
        }
    }

    /**
     * 打印
     */
    public void display() {
        if (first == null) {
            System.out.println("This SingleCiruLinkedList is null.");
            return;
        }
        HeroNode temp = first;
        while(temp != null) {
            System.out.println(temp.toString());
            temp = temp.next;
            if (temp == tail) {
                System.out.println(temp.toString());
                System.out.println(temp.next.toString());
                break;
            }
        }
    }
}
View Code

 

通过循环单向链表解决约瑟夫问题

public class Joseph {
    
    /**
     * @param linkedList 单向循环链表
     * @param begin      起始位置
     * @param interval   间隔
     */
    public static void joseph(SingleCiruLinkedList linkedList, int begin, int interval) {
        // 根据begin找到开始位置
        int i = 0;
        while (i < begin - 1) {
            linkedList.first = linkedList.first.next;
            linkedList.tail = linkedList.tail.next;
            i++;
        }

        while (true) {
            // 如果只有一个或者循环到最后一个,打印跳出循环
            if (linkedList.first == linkedList.tail) {
                System.out.println(linkedList.first.toString());
                break;
            }

            // 每次需要数的次数
            int j = 0;
            while (j < interval - 1) {
                linkedList.first = linkedList.first.next;
                linkedList.tail = linkedList.tail.next;
                j++;
            }
            // 最后first指向的就是目标元素,打印
            System.out.println(linkedList.first.toString());
            // 将目标元素出圈,first指针指向下一个元素,tail的next指针指向first
            linkedList.first = linkedList.first.next;
            linkedList.tail.next = linkedList.first;
        }
    }
}
View Code

 

posted @ 2019-06-17 17:39  Latiny  阅读(220)  评论(0编辑  收藏  举报