約瑟夫環問題的具體描述是:設有編號為1,2,……,n的n個(n>0)個人圍成一個圈,從第1個人開始報數,報到m時停止報數,報m的人出圈,才從他的下一個人起重新報數,報到m時停止報數,報m的出圈,……,如此下去,知道剩余1個人為止。當任意給定n和m后,設計算法求n個人出圈的次序。
一開始看到這這個題目就是覺得這是一個環形的,想到了用鏈表和用指針,然后看題目的要求是使用數組實現。就先暫時放棄用鏈表的辦法,用數組實現之后再用鏈表來實現。
一開始的思路是:
1、建立一個長度為n的數組。
2、取出位置編號為(i+1)*m的數顯示,將位置編號為(i+1)*m的數置0;
3、第一輪取完之后的數再組成一個新的數組,用2的辦法再取;
4、重復3的操作,最后剩下m-1個數字。
經過實際編程調試發現這個辦法很難實現,效率特別低,容易出錯,僅僅是第一輪取完數字再組成一個新的數組就很費勁了,如果數字比較少的話可以直接算出來,如果數據量大,就很麻煩。
后來,就反思一開始的思路其實就是模擬了一個“環“,通過好多數組來拼接一個環。這樣就很麻煩,邏輯上也很混亂,最后也是看了其他人的代碼,覺得用指針的思想到最后一個數的時候跳到第一個就可以了。最早的時候我也有想到過用指針的思想去解決,但是不會用,主要原因是因為我不知道有這樣i = (i + m -1) % n一個公式,公式中i就是出圈的那個數字,知道了這個公式之后就是每次需要把出圈的數字刪除了就可以,繼續用這個公式找到下一個需要出圈的數字。最后找到只剩一個的時候跳出,中間如果找到某一時刻數組的最后一個數字的時候跳到第一個就可以了,這樣就形成了一個環。
根據這個思路完成了下邊的這個程序,這個程序是7個數,報3出圈。
#include <stdio.h> #include <string.h> int main() { int m = 3; int n = 7; int a[7] = {1,2,3,4,5,6,7}; int i; int j; for(i = 0; i < n; i++) { a[i] = i+1; } while (n > 1) { i = (i + m - 1) % n; printf("第一個出圈的是%d\n",a[i]); for(j = i+1; j < n; j++) { a[j-1] = a[j]; } n--; if(i == n) { i = 0; } } printf("最后剩下的是%d\n", a[i]); return 0; }
上邊這段代碼在調試的過程中出了一個非常低級的錯誤,編譯完成后開始運行的時候發現,程序確實在運行但是什么都不顯示,就開始一點一點的調試,發現問題出在了循環部分,發現循環內部是沒有問題的,按照邏輯分析是可以跳出循環的,而且循環中是有顯示的,如果不能跳出循環肯定會連續的顯示,后來就意識到是沒有進入到循環中,又看了很多遍程序才發現是在while(n > 1)這句話后邊加了“;”號,這樣的低級錯誤確實不應該,編程太少,所以找到錯誤花了比較長的時間,還是需要多自主編程,積累經驗。
根據上邊的程序我也進行了一些簡單的修改,能夠實現定制,也就是你可以自己設置輸入的m,n值,代碼如下。
#include <stdio.h> #include <string.h> #define N 100 int main() { int m; int n; printf("請輸入總人數n \n"); scanf("%d",&n); printf("請輸入報的數m \n"); scanf("%d",&m); int a[N] = {0}; int i; int j; int k = 0; for(i = 0; i < n; i++) { a[i] = i+1; } while (n > 1) { i = (i + m - 1) % n; k++; printf("第%d個出圈的是%d\n",k,a[i]); for(j = i+1; j < n; j++) { a[j-1] = a[j]; } n--; if(i == n) { i = 0; } } printf("最后剩下的時%d\n", a[i]); return 0; }
有了第一個代碼,第二個隨機輸入就好實現了,但是在編程過程中還是出現了點問題,因為人數是隨機輸入的,那么n的值就沒辦法確定了,定義數組的時候a[n]這種方式是錯誤的,因此需要定義一個較大的數組,數組的后半段在程序中不使用就可以了。另外scanf函數在使用的時候要記得加”&”,不然會出現段錯誤,如果調試過程中出現了段錯誤,可以看看代碼中是不是忘記加“&”符號了。
約瑟夫環也可以用鏈表的方式來實現,接下來會再用鏈表的方式來實現以下,后邊的博客會實現。
這是新年之后的第一篇博客,新年之后能夠快速的進入學習狀態是一個好的開端。新一年,同時又是編程學習的新的重要的階段,開始自己寫程序,擺脫抄程序的過程。新年中也反思了去年的學習,專注力不夠是一個很大的問題,原因在於上進心不足,眼界不夠,看不到未來讓我覺得迷茫,懈怠。今年是我人生的一個轉折點,提高專注力,用好每天的學習時間,把最能專心學習的時間用在學習上,加強自律。