约瑟夫环问题

约瑟夫环问题


题目

  • 据说著名犹太历史学家Josephus有过一下的故事:
    在罗马人占领乔塔帕特后,39个犹太人与Josephus及他的朋友躲在一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3个人该人必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在了第16个与第31个位置,于是逃过了这场死亡游戏。

问题分析:问题中41个人排成一圈,报数每报到第三个人该人必须自杀,把41个人看成一个链表,而且是一个单向循环链表,把每个人看做一个结点,其所在位置做为数据域position,每个人知道自己的下一个人是谁,为指针域。

定义成员变量size记录剩余人数,接下来用结点的方式初始化该链表,用真实头结点方式来做,有多少人就创建多少结点,用循环方式。借助指针p遍历链表,p从第一个结点开始,即报数为1,p指针移动到第二个结点,第三个结点是要删除的结点,将其指针域指向第四个结点,第三个结点被回收,size- -,p再从第四结点开始,循环上述过程,直到size<=2时,因为剩余两人时,无法淘汰第三个人。最后返回剩余的两个结点的数据域,即幸存的人所在位置。

package DS02.动态链表;

import DS01.动态数组.ArrayList;
import DS01.动态数组.List;

//约瑟夫环问题
public class JosephusLoop {

    private Node head;
    private Node rear;
    private int size;

    public JosephusLoop(int count){
        head=new Node(1,null);
        rear=head;
        rear.next=head;
        for(int i=2;i<=count;i++){
            rear.next=new Node(i,rear.next);
            rear=rear.next;
        }
        size=count;
    }
    public List<Integer> getSurvivePosition(){
        ArrayList<Integer> list=new ArrayList<>();

        Node p=head;
        while(size>2){
            p=p.next;
            Node del=p.next;
            if(del==head){
                head=head.next;
            }
            if(del==rear){
                rear=p;
            }
            p.next=del.next;
            p=p.next;
            size--;
        }
        list.addLast(head.position);
        list.addLast(rear.position);
        return list;
    }

    private class Node{
        int position;
        Node next;
        public Node(){}
        public Node(int position,Node next){
            this.position=position;
            this.next=next;
        }
    }

    public static void main(String[] args) {
        JosephusLoop jp=new JosephusLoop(20);
        List<Integer> list=jp.getSurvivePosition();
        System.out.println(list);
    }

}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值