全排列
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
一:全排列的递归实现
拿123来示例递归算法流程。
123 1和1换
132 1和1换完,接下来把 23当成一个序列,进行2和2换->123 再把3当成一个序列,这时要换的数就是序列的最后一位,输出结果(123)。再回到23序列,2和3换,反复,得到结果。
213 1和2换
231 1和2换完,接下来把 13当成一个序列,进行1和1换->213再把3当成一个序列,这时要换的数就是序列的最后一位,输出结果(213)。再回到13序列,1和3换,反复,得到结果。
321 1和3换
312 同上
实际上全排列就是从第一个数开始,每个数字分别与后面数字进行交换,通过上面的步骤,当交换的那个数,换到了最后一位,输出,实现递归。
代码实现:
#include<vector> #include<iostream> #include<algorithm> #include<iterator> using namespace std; void perm(vector<int> &vec,int k,int m) { if (k == m){ //就是说k从本次perm开始的那个位置换到尾了 即这个子序列只有一个字符时。递归最终实现。 copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, " ")); cout << endl; return; } for (int i = k; i <= m; ++i){ swap(vec[k], vec[i]); perm(vec,k+1,m); //比如 123 1往后换->得到213 321 对于213 再对13序列执行perm swap(vec[k], vec[i]); //将数组回溯到原来的状态 } }
二:去掉重复的全排列的递归实现
去重复的全排列就是从第一个数字起,每个数字分别与它后面非重复出现的数字进行交换。比如122 1和第一个2交换过,就不和第二个2交换了。
在交换时,加一个判断函数即可
bool isSwap(vector<int>&vec, int kbeg, int iend) //要判断从k开始到i 就是说换到现在,该换i了,要看之前出现过i没。 { for (int i = kbeg; i != iend; ++i) // 122 1和第一个2换 先看之前1和2不相等 可以换 if (vec[i] == vec[iend])return false; // 122 1和第二个2换 2之前的2==2,已经换过了,不换了。 return true; } void perm(vector<int> &vec,int k,int m) { if (k == m){ //就是说k从本次perm开始的那个位置换到尾了 即这个子序列只有一个字符时。递归最终实现。 copy(vec.begin(), vec.end(), ostream_iterator<int>(cout, " ")); cout << endl; return; } for (int i = k; i <= m; ++i){ if (isSwap(vec, k, i)){ swap(vec[k], vec[i]); perm(vec, k + 1, m); //比如 123 1往后换->得到213 321 对于213 再对13序列执行perm swap(vec[k], vec[i]); //将数组回溯到原来的状态。 } } }
三:全排列—非递归实现
非递归实现,就要对每一个序列求出一个后继,那么自然而然要有一个终点,即什么时候,序列没有后继。
所以要有序列的大小,最大或最小就没有后继了。
对于升序我们求后继,就是不断的求下一个比该序列大的最小的序列。当序列是最大的序列时,不再有后继。
从后往前搜索,找到一个极大值点(top) vec[top-1] < vec[top] ,
要使得下个数大于前一个数,找一个大于vec[top-1]的数和vec[top-1] 交换,但要使得它最小,取其中最小的但大于num[top-1]的数。
交换之后,top以及其后面的数字还是单调递减的,将其位置对调,得到最小的数。
以 1 2 4 6 5 3 为例, 从后往前找到6 为一个极大值,考虑处理4 和后面的6 5 3 三个数字,大于4 的最小数字为5 ,对换得到5 和 6 4 3,
然后由于后面的6 4 3 还是单调递减的, 将其颠倒得到3 4 6 ,即 1 2 5 3 4 6 为 1 2 4 6 5 3的后继 。
#include<vector> #include<iostream> #include<algorithm> #include<iterator> using namespace std; bool getNext(vector<int>&vec) { auto end = vec.size() - 1; size_t top; while (end != 0){ if (vec[end - 1] < vec[end]){ top = end; //得到峰值 break; } --end; } if (end == 0) return false; //如果是降序排列的 654321 那么没有后继 size_t change = top; //要和top-1交换的数的下标 for (auto i = top; i != vec.size(); ++i){ if (vec[i]>vec[top - 1]) //因为top后面都是递减的,所以最后一个比top-1大的就是最小的 change = i; } swap(vec[top - 1], vec[change]); //找到以后进行交换 reverse(vec.begin() + top, vec.end());//将top往后的降序改为升序 return true; } #include<iostream> #include<vector> #include<algorithm> #include<iterator> #include<fstream> using namespace std; void perm(vector<int> &vec, int k, int m); bool getNext(vector<int>&vec); int main() { ofstream out("all_order"); vector<int>vec = { 1,2,3,4,5,6}; copy(vec.begin(), vec.end(), ostream_iterator<int>(out, " ")); out << endl; while (getNext(vec)){ copy(vec.begin(), vec.end(), ostream_iterator<int>(out, " ")); out<< endl; } system("pause"); return 0; }
posted on 2016-11-30 16:23 ToBeAprogrammer 阅读(213) 评论(0) 收藏 举报
浙公网安备 33010602011771号