排列组合算法

来源:互联网 发布:音乐剪接软件 编辑:程序博客网 时间:2024/04/27 22:30

全排列

递归方法

思路描述

  • 将字符串分为两组,第一组为第一个字符,第二组为剩余的N-1个字符:
    • 确定可以放在第一个位置的字符,即:将第一个字符与之后N-1个字符进行交换得到
    • 对之后的N-1个字符做全排列

算法实现

void permutation(char *str, char *pBegin) {if (*pBegin == '\0') {cout << str << endl;}for (char *pos =  pBegin; *pos != '\0'; pos++) {char tmp = *pos;*pos = *pBegin;*pBegin = tmp;permutation(str, pBegin+1);tmp = *pos;*pos = *pBegin;*pBegin = tmp;}}

字典序法(迭代)

思路描述

  • 在当前序列中,从尾端向前寻找两个相邻元素,前一个记为*i,后一个记为*t,并且满足*i < *t。然后再从尾端寻找另一个元素*j,如果满足*i < *j,即将第i个元素和第j个元素对调,并将t个元素之后的所有元素颠倒排序,即就出下一个序列了。
  • 如果到最后一个排列next_permutation会返回false,但使用了这个方法后,序列会变成字典序列的第一个,如cba变成abc。就可以继续next了,可以参考next_permutation用法。

算法实现

#include <iostream>#include <algorithm>using namespace std;typedef string::iterator StringItr;void itr_swap(StringItr i, StringItr j){    char tmp = *i;     *i = *j;     *j = tmp;}void reverse(StringItr i, StringItr j) {    while (i < j) {        itr_swap(i, j);         ++i, --j;    }   }bool next(string& str) {    StringItr start = str.begin();    StringItr end = str.end() - 1;    if(start == end) {        return false;    }    StringItr i = start;    ++i;    if (i == end)        return false;    i = end;    while(true) {        StringItr t = i;        --i;        if (*i < *t) {            StringItr j = end;            while(!(*i < *j))                j--;            itr_swap(i, j);            reverse(t, end);            return true;        }        if (i == start) {            //all reverse, generate min dictionary            reverse(start, end);            return false;        }    }}void permutation(string& str){    if (str.empty())        return;    StringItr start = str.begin();    StringItr end = str.end();    sort(start, end);    do{        cout << ">>" << str << endl;    }while(next(str));}int main(int argc, char *argv[]){    if (argc == 2) {        string str(argv[1]);        permutation(str);    } else {        string str = "bac";        permutation(str);    }}

组合

递归方法

思路描述

  • 对每一个字符而言,可以选择将其加入组合中,也可以选择不将其加入组合中:
    • 若选择加入组合,则从后N-1个字符中,选择m-1个字符加入到组合中
    • 若不选择加入组合,则从后N-1个字符中,选择m个字符加入到组合中

算法实现

#include <iostream>using namespace std;typedef string::iterator StringItr;void _combination(string& str, StringItr current, int m, char *b, int index){    if (current == str.end())        return;        //don't choose current pos    _combination(str, current+1, m, b, index);    //choose current pos    b[++index] = *current;    _combination(str, current+1, m, b, index);    if (index == (m-1)) {        b[m] = '\0';        cout << b << endl;    }   }void combination(string& str) {    char b[str.size() + 1];     for (int i = 1; i < str.size(); i++ ) {         _combination(str, str.begin(), i, b, -1);    }   }int main(int argc, char *argv[]){    if (argc == 2) {        string str(argv[1]);        combination(str);    } else {        string str = "abc";        combination(str);    }       return 0;}


迭代方法-01法

思路描述

  • 展开一个数组,其下标表示1~N个数,数组元素的值为1表示其代表的数被选中,为0表示没被选中。
    • 初始化:将数组前M个元素置1,表示第一个组合为前M个数
    • 然后从左到右扫描数组元素值为“10”组合,找到第一个“10”组合后将其变为01组合,同时将左边所有的“1”全部移动到数组的最左端。
    • 当第一个1移动到数组的n-m的位置时,M个1全部移动到最右端,就得到了最后一个组合

算法实现

#include <iostream>using namespace std;void print_result(string& str, int *loc){    int length = str.size();    for (int i = 0; i < length; i++) {        if (loc[i])            cout << str[i];    }       cout << endl;}int first_1_pos(int *loc, int length){    for (int i = 0; i < length; i++) {        if(loc[i]) {            return i;        }       }       return -1; }int first_10_pos(int *loc, int length){    for (int i = 0; i < length - 1; i++) {        if(loc[i] && loc[i+1] == 0) {            return i;        }    }    return -1;}void swap(int &a, int &b){    a = b + a;    b = a - b;    a = a - b;}void move_1_to_left(int *loc, int end){    for (int old = 0, pos = 0; old < end; old++) {        if (loc[old] && pos != old) {            loc[pos++] = 1;            loc[old] = 0;        }    }}void _combination(string& str, int *loc, int m){    //initialize loc array    int length = str.size();    for (int i = 0; i < length; i++) {        if (i < m)            loc[i] = 1;        else            loc[i] = 0;    }    print_result(str, loc);    int first_1 = first_1_pos(loc, length);    int end_condition = length - m;    //loop to search all m combinations    while (first_1 != end_condition) {        int first_10 = first_10_pos(loc, length);        swap(loc[first_10], loc[first_10+1]);        move_1_to_left(loc, first_10);        print_result(str, loc);        first_1 = first_1_pos(loc, length);    }}void combination(string& str){    int length = str.size();    int loc[length];    for (int i = 1; i < length; i++) {        _combination(str, loc, i);    }}int main(int argc, char *argv[]){    if (argc == 2) {        string str(argv[1]);        combination(str);    } else {        string str = "abc";        combination(str);    }    return 0;}







0 0
原创粉丝点击