1. 程式人生 > 其它 >全排列,迴圈,交換,遞迴,回溯

全排列,迴圈,交換,遞迴,回溯

技術標籤:筆記演算法遞迴法

排列問題

關鍵詞:迴圈,交換,遞迴,回溯

舉例

eg: {1, 2, 3}的全排列是多少?
利用高中全排列的知識,做出如下解釋:第一個位置可放3個元素,第二個位置還剩下2個元素可放,最後放一個元素,得到3 * 2 * 1 = 6 种放法。
那麼如何用程式碼表示上面的放法呢?
第一個位置三种放法,首先怎麼得到三個資料呢?
第一次遍歷,自己和自己交換,第二次遍歷,自己和第二個數交換,第三次,自己和第三個數交換。
int k = 0;
int m = 2;
for(int i = k; i <= m; i++) {
	swap(list[i], list[k]
; } /* 這裡我們看到要想第一次得到自己,第二次得到第二個數, 第三次得到第三個數的前提是,每一次交換必須保證是{1,2,3}的初始態, 下面解釋怎麼復原*/
那麼第二個位置兩種方法怎麼來表示呢,和第一個位置一樣一定也是迴圈,聰明的小夥伴一定發現了,下標起始位置不同。問題又來了,第一個位置進行了第一次交換後第二個位置怎麼進行第一次交換?
遞迴鴨!
Perm(list, k + 1, m)
那麼每次怎麼進行復原,比如{1, 3, 2},下一個全排列是多少,下一個狀態一定是{2, 1, 3},首先我們得還原為{1,2,3},怎麼還原?第三次迴圈結束條件不滿足,不進入迴圈體,返回上一級,我們剛剛怎麼交換的就怎麼交換回來,再swap()一下。這就是回溯的體現。
swap(list[k],list[i]);
那麼到這裡,我們其實已經得到程式碼的核心部分,剩下的部分就是出口問題,我們想想,最後一個數用不用交換???是不是不用,倒數第二個數的交換,是不是就已經完成了,所以出口就是倒數第二個數完成後,準備進入下一次交換時,遞迴返回。
程式碼如下:
template <class Type>
void Perm(Type list[], int k, int m) {
	if( k == m) {
		for(int i = 0; i <= m; i++) {
			cout << list[i];
		}
		cout <<
endl; } else { for(int i = k; i <= m; i++) { swap(list[i], list[k]); Perm(list, k + 1, m); swap(list[i], list[k]); } } } int main() { int list[3] = {1,2,3}; Perm(list, 0, 2); return 0; }

用腦子跑一下:
{1,2,3}
{1,3,2}
{2,1,3}
{2,3,1}
{3,2,1}
{3,1,2}

電腦結果如下:
在這裡插入圖片描述