java---表、栈和队列

题目3

Josephus问题(Josephus problem)是下面的游戏:N个人编号从1到N,围坐成一个圆圈。从1号开始传递一个热土豆。经过M次传递后拿着热土豆的人被清除离座,围坐的圆周紧缩,由坐在被清除的人后面的人拿起热土豆继续进行游戏。最后剩下的人取胜。因此,如果M=0和N=5,则游戏人依序被消除,5号游戏人获胜。如果M=1和N=5,那么被清除的人的顺序是2,4,1,5。
a. 编写一个程序解决M和N在一般值下的Josephus问题,应使程序尽可能地高效率,要确保能够清除各个单元。
b. 你的程序的运行时间是多少?

>

分析:当热土豆经过M次传递后,需要找出土豆所在的位置,然后将该位置上的元素删除掉,表中元素总数自减1.
为了提高效率,我们可以根据所要传递的次数M的大小和人数N的多少,进行分类查找:
第一类,当 M<=N/2 时,按照从前向后的顺序进行遍历,此时,如果遍历到最后一个元素时,则需要将迭代器的引用放置到表头处;
第二类,当 M>N/2 时,按照从后向前的顺序进行遍历,此时,如果遍历到第一个元素时,则需要将迭代器的引用放置到表尾处;
根据两类情况下的查找顺序可知,我们既要检索后面的索引,也要检索前面的索引,因此,使用ListIterator接口的迭代器listIterator。
另外,由于在传递的过程构成了一个圆圈,因此传递的次数可以表示为:mprime = m%n;
注:表的索引是从0开始的。
当前项的概念是通过把迭代器看做是在对next的调用所给出的项和对previous的调用所给出的项之间而抽象出来的。如图所示:

java代码
public static void pass(int m,int n)
    {
        int i,j,mprime,numLeft;

        ArrayList<Integer> L = new ArrayList<Integer>();
        for(i=1;i<=n;i++){L.add(i);}

        ListIterator<Integer> iter = L.listIterator();
        Integer item = 0;

        numLeft = n;//剩余人数
        mprime = m%n;//传递的次数

        for(i=0;i<n;i++)
        {
            mprime = m%numLeft;
            //分类思想,提高效率。
            if(mprime <= numLeft/2)
            {
                if(iter.hasNext())
                    item = iter.next(); //第一次调用next()时,返回序列的第一个元素。

                //热土豆经过mprime次传递之后,查找出持有热土豆人的编号。
                for(j =0;j < mprime;j++)
                {
                    //当热土豆传到最后一个人时,需要传递到当前第一个人的手里。
                    if(!iter.hasNext())
                        iter = L.listIterator(); //返回序列第一个(即第0个)元素的位置之前。
                    //向后查找一次
                    item = iter.next();  
                }
            }
            else
            {
                for(j=0;j < numLeft-mprime;j++)
                {
                    //当热土豆传到第一个人时,需要传递到当前最后一个人的手里。
                    if(!iter.hasPrevious())
                        iter = L.listIterator(L.size());//返回到序列最后一个元素的位置和倒数第二个元素位置之间。
                    //向前查找一次
                    item = iter.previous();
                }
            }
            System.out.println("Removed "+item+", the people left is...");
            iter.remove();//刪除由next()或previous()返回的最后一個元素。

            if(!iter.hasNext())
                {iter = L.listIterator();}//从表尾返回到表头,此时已经传递了一次。

            for(Integer x:L)
                System.out.print(x+" ");
            System.out.println();
            numLeft--;

        }

    }

>

- 运行结果如下所示:


When M =0,N=5,the process is as follow:
Removed 1, the people left is…
2 3 4 5
Removed 2, the people left is…
3 4 5
Removed 3, the people left is…
4 5
Removed 4, the people left is…
5
Removed 5, the people left is…


When M =1,N=5,the process is as follow:
Removed 2, the people left is…
1 3 4 5
Removed 4, the people left is…
1 3 5
Removed 1, the people left is…
3 5
Removed 5, the people left is…
3
Removed 3, the people left is…


When M =2,N=5,the process is as follow:
Removed 3, the people left is…
1 2 4 5
Removed 1, the people left is…
2 4 5
Removed 5, the people left is…
2 4
Removed 2, the people left is…
4
Removed 4, the people left is…


When M =3,N=5,the process is as follow:
Removed 4, the people left is…
1 2 3 5
Removed 3, the people left is…
1 2 5
Removed 5, the people left is…
1 2
Removed 2, the people left is…
1
Removed 1, the people left is…


When M =4,N=5,the process is as follow:
Removed 5, the people left is…
1 2 3 4
Removed 1, the people left is…
2 3 4
Removed 3, the people left is…
2 4
Removed 4, the people left is…
2
Removed 2, the people left is…


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值