关于全排列算法,分为两种:可重复的全排列和不包含重复的元素的全排列
一、含重复元素的全排列
算法思路:
(1)n个元素的全排列=(n-1个元素的全排列)+(另一个元素作为前缀);
(2)出口:如果只有一个元素的全排列,则说明已经排完
(3)不断将每个元素放作第一个元素,然后将这个元素作为前缀,并将其余元素继续全排列,等待出口,出口出去后还需要还原数组
#include <iostream>
#include <stdlib.h>
#include <vector>
using namespace std;
void swap(vector<int>&a, int i, int j)
{
int temp;
temp = a[j];
a[j] = a[i];
a[i] = temp;
}
void prem(vector<int>&a, int start, int end, vector<vector<int>>&ret)
{
if (start == end)
{
vector<int>::iterator iter;
for (iter = a.begin(); iter < a.end(); iter++)
{
cout << (*iter) << " ";
}
cout << endl;
ret.push_back(a);
return;
}
else
{
for (int i = start; i <= end; i++)
{
swap(a, start, i);
prem(a, start + 1, end, ret); //每次选择子后一个元素为开始第一个元素
swap(a, i, start);
}
}
}
int main()
{
vector<int> v = { 1,2,3,4};
vector<vector<int>> ret;
int start = 0, end = v.size()-1;
prem(v, start, end, ret);
vector<vector<int>>::iterator iter;
cout << endl;
system("pause");
return 0;
}
二、不包含重复元素
因为排序是前缀加上后缀,所以要保证前缀每次都不一样才可以,也就是说交换后不能重复,所以在交换前要进行排查
只要从start开始到end(不包括end包括start)中间的元素与end元素相等,那么前缀就有可能相同,所以要去掉
去重的规则:去重的的全排列就是与当前元素 i 交换的元素 j 不能与 i~j 之间的元素相同,这样才可以保证前缀不一样。因此我们在上一题的基础上再完善下就可以
#include <iostream>
#include <stdlib.h>
#include <vector>
using namespace std;
bool IsSwap(vector<int>& a, int start, int end)
{
for (int i = start; i < end; i++)
if (a[i] == a[end])
return false;
return true;
}
void swap(vector<int>&a, int i, int j)
{
int temp;
temp = a[j];
a[j] = a[i];
a[i] = temp;
}
void prem(vector<int>&a, int start, int end, vector<vector<int>>&ret)
{
if (start == end)
{
vector<int>::iterator iter;
for (iter = a.begin(); iter < a.end(); iter++)
{
cout << (*iter) << " ";
}
cout << endl;
ret.push_back(a);
return;
}
else
{
for (int i = start; i <= end; i++)
{
if (IsSwap(a, start, i))
{
swap(a, start, i);
prem(a, start + 1, end, ret); //每次选择子后一个元素为开始第一个元素
swap(a, i, start);
}
}
}
}
int main()
{
vector<int> v = { 2,2,3,4};
vector<vector<int>> ret;
int start = 0, end = v.size()-1;
prem(v, start, end, ret);
vector<vector<int>>::iterator iter;
cout << endl;
system("pause");
return 0;
}