字串的全排列詳解,遞迴 非遞迴

2021-07-16 06:41:37 字數 2608 閱讀 3272

輸入乙個字串,列印出該字串中字元的所有排列。例如輸入字串abc,則輸出由字元a,b,c所能排列出來的所有字串abc,acb,bac,bca,cab和cba

首先,我們固定第乙個字元a,求後面兩個字元bc的排列

當兩個字元bc排列求好之後,我們把第乙個字元a和後面的b交換,得到bac,接著我們固定第乙個字元b,求後面兩個字元ac的排列

現在是把c放在第乙個位置的時候了,但是記住前面我們已經把原先的第乙個字元a和後面的b做了交換,為了保證這次c仍是和原先處在第乙個位置的a交換,我們在拿c和第乙個字元交換之前,先要把b和a交換回來。在交換b和a之後,再拿c和處於第一位置的a進行交換,得到cba。我們再次固定第乙個字元c,求後面兩個字元b、a的排列

既然我們已經知道怎麼求三個字元的排列,那麼固定第乙個字元之後求後面兩個字元的排列,就是典型的遞迴思路了

#include"stdafx.h"

#include"iostream"

#include using namespace std;

int count; //統計全排列的個數

void swap(char *str, int a, int b)

void permutation_process(char *str, int begin, int end) else

} }

int _tmain(int argc, _tchar* argv)

下面這張圖給出了遞迴的過程

如果字串中有重複字元的話,上面的那個方法肯定不會符合要求的,因此現在要想辦法來去掉重複的數列。

由於全排列就是從第乙個數字起每個數分別與它後面的數字交換。我們先嘗試加個這樣的判斷——如果乙個數與後面的數字相同那麼這兩個數就不交換了。例如abb,第乙個數與後面兩個數交換得bab,bba。然後abb中第二個數和第三個數相同,就不用交換了。但是對bab,第二個數和第三個數不同,則需要交換,得到bba。由於這裡的bba和開始第乙個數與第三個數交換的結果相同了,因此這個方法不行。

換種思維,對abb,第乙個數a與第二個數b交換得到bab,然後考慮第乙個數與第三個數交換,此時由於第三個數等於第二個數,所以第乙個數就不再用與第三個數交換了。再考慮bab,它的第二個數與第三個數交換可以解決bba。此時全排列生成完畢!

這樣,我們得到在全排列中去掉重複的規則:

去重的全排列就是從第乙個數字起,每個數分別與它後面非重複出現的數字交換。

#include "stdafx.h"

#include"iostream"

#include using namespace std;

int count; //統計全排列的個數

void swap(char *str, int a, int b)

int is_swap(char *str, int begin, int k)

}

return flag;

}

void permutation_process(char *str, int begin, int end)

} }

} int _tmain(int argc, _tchar* argv)

要考慮全排列的非遞迴實現,先來考慮如何計算字串的下乙個排列。如"1234"的下乙個排列就是"1243"。只要對字串反覆求出下乙個排列,全排列的也就迎刃而解了。

如何計算字串的下乙個排列了?來考慮"926520"這個字串,我們從後向前找第一雙相鄰的遞增數字,"20"、"52"都是非遞增的,"26 "即滿足要求,稱前乙個數字2為替換數,替換數的下標稱為替換點,再從後面找乙個比替換數大的最小數(這個數必然存在),0、2都不行,5可以,將5和2交換得到"956220",然後再將替換點後的字串"6220"顛倒即得到"950226"。

如果達到這個數的最大,比如1234-4321,這個時候就結束整個迴圈。

如果輸入是乙個非最小數,如1324,則將它轉換為最小數,如1234,再進行排序。排序演算法用快排,可以自己寫乙個,如果快排不會的話,就先看會再來接著看,或者自己想乙個靠譜的演算法,也可以直接用vc庫中的qsort(s , n , sizeof(s[0]) , cmp);各引數是什麼意思就自己在下面多花點時間吧。

ok,下面看**分析

//全排列非遞迴

#include"stdafx.h"

#include#include#includeusing namespace std;

#include//反轉區間

void reverse(char* pbegin , char* pend)

//下乙個排列

bool next_permutation(char a)

} reverse(a , pend); //如果沒有下乙個排列,全部反轉後返回false

return false;

}

int cmp(const void *a,const void *b)

int main(void)

while(next_permutation(str));

return 0;

}

C 演算法 字串全排列 非遞迴 非遞迴

字串的全排列是面試中相對而言必要重要的演算法,有兩種實現方法 遞迴,非遞迴 替換點 從字串的最後一位開始,找到第乙個逆序的字串,如 54312 那麼從後向前第乙個逆序為12,那個1就是替換值,替換值得位置就是替換點。非遞迴演算法思想 對於乙個字串4231,這個字串中排列組合中1234是最小的數,43...

字串全排列 非遞迴實現

乙個演算法命題 給定字串s 0 n 1 設計演算法,列舉s的全排列。如 123,全排列就是 123,132,213,231,312,321 由123的全排列 123,132,213,231,312,321可知,這個全排列大小是有序的。也就是說,從最小的開始排列,每次只找比當前排列大一點的序列即可,這...

遞迴 字串全排列 全排列

在高中階段我們已經通過大量的習題了解了排列和組合。但是有時候我們研究的不是由排列和組合算出來的數字,研究的是生成排列和組合。即,把集合中元素所有的排列和組合全部列出來,然後研究這些序列的性質。今天我用兩種方法講一下如何生成排列。注意我們這裡涉及的順序都是序列的字典序。序列的字典序 設有兩個序列,第乙...