丢手帕问题 (约瑟夫问题)Java实现
问题:
丢手帕游戏是约瑟夫问题的一个变种,游戏很简单,N个小孩围成一个圈,标号为1到N,从编号为m的小孩开始报数,报到第L个小孩退出游戏,然后下一个小孩继续从1开始报数,数到第L个小孩退出游戏,如此循环,直到剩下最后一个小孩是胜利者.
使用环形链表方式解决问题:
代码如下:
/** * 描述: * @作者:niexiaohui * @创建时间:2016年12月27日 * @修改记录: */ public class Test { public static void main(String[] args) { long starttime=System.currentTimeMillis(); CircleLinkList game=new CircleLinkList(10000, 99, 533); long endtime=System.currentTimeMillis(); game.play(); long time2=System.currentTimeMillis(); System.out.println("创建链表用了"+(endtime-starttime)/1000.0+"秒"); System.out.println("玩游戏共用了"+(time2-starttime)/1000.0+"秒"); } } class Child{ protected int no; protected Child nextChild; public Child(int no){ this.no=no; } } class CircleLinkList{ /** * 参与游戏人数 */ private int playBoys; /** * 从第几个开始数 */ private int startIndex; /** * 数几个小孩退出 */ private int countNum; //首个小孩 private Child firstChild; //标识当前小孩 private Child temp; /** * * @param playBoys 参与游戏人数 * @param startIndex 从第几个开始数 * @param countNum 数几个小孩退出 */ public CircleLinkList(int playBoys, int startIndex, int countNum) { super(); this.playBoys = playBoys; this.startIndex = startIndex; this.countNum = countNum; createList(); } /** * 创建循环链表 */ private void createList() { for (int i = 1; i <=playBoys; i++) { if (i==1) {//第一个小孩 Child child=new Child(i); this.firstChild=child; this.temp=child; }else if (i==playBoys) {//最后一个小孩 Child child=new Child(i); this.temp.nextChild=child; this.temp=child; this.temp.nextChild=this.firstChild;//最后一个小孩的下一个小孩指向第一个小孩 }else { Child child=new Child(i); this.temp.nextChild=child; this.temp=child; } } } /** * 玩游戏 */ public void play(){ temp=firstChild; //先找到从第几个小孩开始数 for (int i = 1; i < startIndex; i++) { temp=temp.nextChild; } System.out.println("游戏开始,从第"+temp.no+"个小孩开始数,数到第"+this.countNum+"个小孩退出游戏"); while (this.playBoys>1) { //找到要退出游戏的前一个小孩 for (int i = 1; i < countNum-1; i++) { temp=temp.nextChild; } //当前temp是要退出的前一个小孩 Child leaveChild=temp.nextChild;//要退出的小孩 System.out.println("当前退出的小孩编号为:" +leaveChild.no); temp.nextChild=leaveChild.nextChild; if (leaveChild.no==firstChild.no) {//如果要退出的小孩是第一个小孩,则将第一个小孩重置为退出小孩的下一个小孩 this.firstChild=leaveChild.nextChild; } temp=temp.nextChild; this.playBoys--;//玩游戏人数少一个 } System.out.println("最后剩下的小孩是:"+ temp.no); } }
代码虽然不少,但是并不难懂,有过一点数据结构基础的还是很容易理解的.
使用数组方式解决问题:
代码如下:
/** * 描述: * * @作者:niexiaohui * @创建时间:2017年1月11日 * @修改记录: */ public class Test4 { public static void main(String[] args) throws InterruptedException { long starttime = System.currentTimeMillis(); int childrens=10000;//玩游戏的小孩总数 int countNum=533;//数第几个小孩退出游戏 int startNum=99;//开始从第几个人开始数 int count=1;//计数器 int [] arrays=new int[childrens]; for (int i = 0; i < arrays.length; i++) {//为数组初始化值 arrays[i]=1; } loop:while(true){ for (int i = 0; i < arrays.length; i++) { if (i<startNum-1) {//第一次循环找到从第几个小孩开始数数 continue; } startNum=0;//开始后将startNum清零 if (arrays[i]!=0) {//值为0的表示已经退出游戏 if (count%countNum==0) {//数到的小孩退出游戏 if (childrens==1) { System.out.println("游戏胜利的小孩编号为:"+(i+1)); break loop; } arrays[i]=0;//退出游戏的小孩值设为0 count=0;//计数器清零,重新计数 childrens--;//玩游戏的人数减一 System.out.println("编号为"+(i+1)+"的小孩退出游戏"); } count++; } } } long time2 = System.currentTimeMillis(); System.out.println("玩游戏共用了" + (time2 - starttime)/1000.0 + "秒"); } }
用数组方式解决问题代码少了很多,效率上,我大致比较了下,随着数到第L个小孩退出游戏,即L的增大,链表的速度会提升,相反数组会下降,如果L值很小的话,数组的效率是高于链表的效率的.
生来奔走万山中,踏尽崎岖路自通