首页 > 技术文章 > 全排列合集

kind064100611 原文

不得不佩服这位大哥,算法钻研的这么细,说的还很清楚:http://blog.csdn.net/morewindows/article/details/7370155    算法并非照着贴来的,是我看了他的说明自己写的。

去掉重复的非递归全排列:

如何计算字符串的下一个排列了?来考虑"926520"这个字符串,我们从后向前找第一双相邻的递增数字,"20"、"52"都是非递增的,"26 "即满足要求,称前一个数字2为替换数,替换数的下标称为替换点,再从后面找一个比替换数大的最小数(这个数必然存在),0、2都不行,5可以,将5和2交换得到"956220",然后再将替换点后的字符串"6220"颠倒即得到"950226"。

#include <string>
#include <algorithm>
#include <iostream>

using namespace std;

class NRP
{
private:
    string __str;
    int __length, __num;
public:
    NRP() {
        cout<<"please input a string: 
";
        while (cin >>__str) {
            __num = 0;
            __length = __str.length();
            sort(__str.begin(), __str.end());
            cout<<"start to output
";
            do
            {
                cout<<__str<<endl;
                __num++;
            } while (NextPermutation() == true);
            cout<<"the total number of permutation is :"<<__num<<endl;
            cout<<"please input a string: 
";
        }
    }

    ~NRP(){}

    bool NextPermutation() {
        int i;
        for (i = __length-2; i>=0 ; i--)
        {
            if (__str[i] < __str[i+1])
            {
                char c = '';
                int k;
                for (int j = i+1; j< __length; j++)
                {
                    if (__str[j] > __str[i])
                    {
                        if (c == '')
                        {
                            c = __str[j];
                            k = j;
                        }
                        else if (c >= __str[j]) //当存在重复字符时,也必须交换
                        {
                            c = __str[j];
                            k = j;
                        }
                    }
                }
                swap(__str[i], __str[k]);
                reverse(__str.begin()+i+1, __str.end());
                return true;
            }
        }
        return false;
    } 

};

void main()
{
    NRP nrp;
}

去掉重复的递归全排列:

这样我们也得到了在全排列中去掉重复的规则——去重的全排列就是从第一个数字起每个数分别与它后面非重复出现的数字交换。用编程的话描述就是第i个数与第j个数交换时,要求[i,j)中没有与第j个数相等的数。

#include <iostream>
#include <vector>
#include <string>

using namespace std;

class Permutation
{
private:
    int n,sum;
    string str;
public:
    Permutation()
    {
        cout<<"Please input a string: "<<endl;
        while (cin>>str)
        {
            n = str.length();
            sum = 0;
            getPerm(0);
            printSum();
            cout<<"Please input a string: "<<endl;
        }
    }

    ~Permutation(){}

    bool IsSwap(int nBegin, int nEnd)
    {
        for (int i = nBegin; i < nEnd; i++)
        {
            if (str[i] == str[nEnd])
            {
                return false;
            }
        }
        return true;
    }
    void getPerm(int k)
    {
        if (k == n)
        {
            sum++;
            cout<<str<<endl;
        }
        else
        {
            for (int i = k; i < n;i++)// 如果只有4个元素  第一次为 swap(0,0)  swap(0,1) swap(0,2) swap(0,3)
            {
                if (IsSwap(k, i) == true)
                {
                    swap(str[i],str[k]);
                    getPerm(k+1);
                    swap(str[i],str[k]);
                }
            }
        }
    }
    void printSum()
    {
        cout<<sum<<endl;
    }
};

void main()
{
    Permutation perm;
}

纯STL的去掉重复的全排列:

#include <iostream>
#include <algorithm>
#include <string>

using namespace std;

void main()
{
    string str;
    cin >> str;
    sort(str.begin(), str.end());
    cout << str << endl;
    while (next_permutation(str.begin(), str.end()))
    {
        cout << str << endl;
    }
}

  

推荐阅读