生成可重集的排列

在上篇博文中介紹了,如何輸出1~n的全排列。在這篇博文裏,小編接着做出補充——生成可重集的排列。
如果把上篇博文中的問題改成,輸入數組A,並輸出數組中各元素的全排列,則需要對上述程序做出修改。首先,我們需要把A加到函數的參列表裏。然後,把代碼中的if(A[j]==i)和A[cur]=i分別改成if(A[j]==p[i])和A[cur]=p[i]。這樣只需要將數組按從小到大的順序排列後,調用函數即可。
下面介紹這個方法中存在的問題,並做出說明。
這個方法看上去不錯,但是如果輸入爲1 1 1後,程序什麼也輸出不出來。原因在於,這樣禁止A數組中出現重複,而在A中本來就有元素重複,這個限制是錯誤的。那麼,我們該如何解決這個問題呢?我們很自然的就想到統計A[0]~A[cur-1]中A[i]出現的次數c1以及在數組中出現的次數c2,只要c1<c2,就能遞歸調用。
介紹到這裏,是否這個算法就真的完美了呢?答案是否定的。就剛纔的輸入1 1 1這個例子而言,程序輸出的結果爲27個1 1 1。程序輸出的結果中沒有遺漏了,但是出現了大量的重複。這顯然不是我們想要的結果。出現重複的原因是因爲:先是把第一個1作爲開頭遞歸調用結束後,以第二個1作爲開頭,依次類推,知道程序運行結束爲止。但是,3個1是相同的,我們不該遞歸3次,而是應該遞歸一次即可。
下面,我們就來探討一下,如何解決這個問題。這個算法在於,我們枚舉的下標i應該不重複,同時也應該沒有遺漏的取遍A[i]的值。由於,我們A數組已經排過序,所以只需要檢查A的第一個元素和所有“與前一個元素不同”的元素,即在for(i=0;i<n;i++)和其後面的花括號之前加上if(!i||A[i]!=A[i-1])即可。
小編建議讀者,自己在電腦中實現代碼,體會其中的方法。
由於小編能力有限,歡迎讀者批評指正。
小編將在下期帶來圖論中的一個重要算法DFS以及應用回溯思想的例子。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章