問題:
丟手帕游戲是約瑟夫問題的一個變種,游戲很簡單,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值很小的話,數組的效率是高於鏈表的效率的.