求集合的全排列

求集合的全排列

旋转法:

对于含有n个元素的数组,旋转n次之后他就会恢复原状。

Alt text

选择法

假如给定的集合是ABC,那么我们可以先想一下最终的结果形式可以认为是所有以A开头,以B开头和以C开头的三种。按此递归的继续下去。

以A开头的,后面还有BC,接下来的第二个字符分为两种,以B开头的和以C开头的。那么结果就是ABC,ACB

以B开头的, 结果就是BAC和BCA

以C开头的, 结果是CAB和CBA

字典顺序

设有排列2763541,按照字典序排列,它的下一个排列是谁?
(1) 2763541 [找最后一个正序35]
(2) 2763541 [找3后面比3大的最后一个数4]
(3) 2764531 [交换3,4的位置]
(4) 2764135 [把4后面的531反序排列为135]

< header>

#include<iostream>
#include<algorithm>
#include<iterator>
#include<vector>

using namespace std;

< common used func >

void createArray(vector<int> *array, int const & n){

    for (int i(1); i <= n; i++){
        (*array)[i - 1] = i;
    }

}

< 旋转法 >

//对容器中的前n个数进行旋转。
void rotate(int const &n, vector<int>*before, vector<int>*after){

    copy(before->begin(), before->begin()+n-1, after->begin() + 1);
    (*after)[0] = (*before)[n-1];
}

void permutation_v1_Helper(vector<int> *set, int const &n, vector<vector<int>> &result){

    if (n == 1){//长度为1,不再旋转。
        result.push_back(*set);
        return;
    }

    permutation_v1_Helper(set, n - 1, result);//对set的前n-1个继续旋转。

    vector<int> *temp1,*temp2;
    temp1 = set;
    for (int i(1); i < n; i++){//旋转n次就会回到原状,所以对set一共旋转n-1次
        temp2 = new vector<int>(*temp1);
        rotate(n, temp1, temp2);
        temp1 = temp2;
        permutation_v1_Helper(temp1, n - 1, result);//对旋转之后的容器的前n-1个数继续旋转
    }

}

void permutation_v1(int const &n, vector<vector<int>> &result){

    //生成数组
    vector<int> *temp = new vector<int>(n);
    createArray(temp, n);

    //递归
    permutation_v1_Helper(temp, n, result);

}

< 选择法 >

void permutation_v2_Helper(vector<int> *set, int const &n, vector<vector<int>> &result){

    if (n==1) {
        vector<int> *temp = new vector<int>(*set);
        result.push_back(*temp);
        return;
    }

    permutation_v2_Helper(set, n-1, result);//

    for (int i(0); i <n-1; i++){
        swap((*set)[i], (*set)[n-1]);//STL--交换
        permutation_v2_Helper(set,n-1, result);
        swap((*set)[i], (*set)[n - 1]);//STL--交换回来
        //在递归过程中只要发生过交换,都对应有一个相同的交换,使其复原。
    }
}

void permutation_v2(int const &n, vector<vector<int>> &result){

    //生成数组
    vector<int> *temp = new vector<int>(n);
    createArray(temp, n);

    //递归
    permutation_v2_Helper(temp, n, result);

}

< 字典顺序: Fischer-Kruse 方法 >

//按字典排序---参见组合数学相关内容
//Fischer - Kruse 方法
void permutation_v3(int const &n, vector<vector<int>> &result){

    //生成数组{1,2,3,..,n}
    vector<int> *temp = new vector<int>(n);
    createArray(temp, n);

    result.push_back(*temp); //{1,2,3,..,n}

    int swapPos1, swapPos2; 
    while (true){

        //find swapPos1
        for (swapPos1 = n - 1; swapPos1 > 0 && (*temp)[swapPos1] < (*temp)[swapPos1 - 1]; swapPos1--);
        swapPos1--;

        //结束条件
        if (swapPos1 < 0)break;

        //find swapPos2
        for (swapPos2 = n - 1; swapPos2 > swapPos1 && (*temp)[swapPos1] > (*temp)[swapPos2]; swapPos2--);

        //交换
        swap((*temp)[swapPos1], (*temp)[swapPos2]);

        //重排---得到字典序列中的下一个排列
        //我这里直接使用sort,没有充分利用数组是逆序的这个性质,其实最好写一个排序逆序的函数,
        //对于大数组来说,这能大幅度提高排序的速度。
        sort(temp->begin()+swapPos1+1,temp->end());//temp->begin()+swapPos1+1==>(*temp)[swapPos1+1]

        //记录到result中
        result.push_back(*new vector<int>(*temp));

    }

}

< main >

int main(){


    vector<vector<int>> result;
    int n;
    cout << "请输入集合元素个数n:" << endl;
    cin >> n;


    permutation_v1(n, result);
    cout << "permutation_v1的结果:-----------------------" << endl;
    for (int i(0); i < result.size(); i++){
        cout << "{";
        copy(result[i].begin(), result[i].end(), ostream_iterator<int>(cout));
        cout << "}";
        cout << endl;
    }
    result.clear();

    permutation_v2(n, result);
    cout << "permutation_v2的结果:-----------------------" << endl;
    for (int i(0); i < result.size(); i++){
        cout << "{";
        copy(result[i].begin(), result[i].end(), ostream_iterator<int>(cout));
        cout << "}";
        cout << endl;
    }
    result.clear();

    permutation_v3(n, result);
    cout << "permutation_v3的结果:-----------------------" << endl;
    for (int i(0); i < result.size(); i++){
        cout << "{";
        copy(result[i].begin(), result[i].end(), ostream_iterator<int>(cout));
        cout << "}";
        cout << endl;
    }
    result.clear();

    system("pause");
    return 0;
}   
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值