zoukankan      html  css  js  c++  java
  • generating permunation

    generating permunation——全排列(算法汇总)

    复制代码

    #include <iostream> #include <string> #include <vector> #include <list> #include <queue> #include <iterator> #include <algorithm> using namespace std; #define MAX 10 int used[MAX]; //用来标记数字是否已经在前面使用过 int result[MAX]; //存放结果 int array[MAX] = {1,2,3,4,5,6,7,8,9,10}; void swap(int x, int y){ int temp = array[x]; array[x]=array[y]; array[y]=temp; return; } template<typename T> void printArray(T array[], int size){ int i; for (i=0;i<size;i++) cout << array[i] << " "; cout << endl; return; } /*递归(非字典序)*/ template<typename T> void recur_permute(T array[], int begin, int end) { int i; if (begin==end) { printArray(array, end+1); return; } else{ //for循环遍历该排列中第一个位置的所有可能情况 for (i=begin; i<=end; i++){ swap(begin, i); //循环变换第一个位置 recur_permute(array, begin+1, end); //DFS swap(begin, i); //回溯,保持原排列 } } } /*递归(字典序)*/ template<typename T> void lexi_recur_permute(T array[], int begin, int end) { int i; if (begin == end+1) { printArray(result, end+1); return; } else{ for (i=0; i<=end; i++){ if(!used[i]) //没有标记 { used[i]=1; //标记 result[begin]=array[i]; //记录结果 lexi_recur_permute(array, begin+1, end); used[i]=0; //回溯 } } } } /*STL(字典序)*/ template<typename T> void stl_permute(T array[], int size) { vector<T>::iterator begin, end; vector<T> Pattern(size) ; ostream_iterator<T> out_it(cout, " ") ; //int size=sizeof(array)/sizeof(T); for(int i=0; i<size; i++) Pattern[i]=array[i]; begin = Pattern.begin() ; end = Pattern.end() ; do { copy(begin, end, out_it) ; cout << endl ; }while ( next_permutation(begin, end) ); } int get_factorial(int n) { if(1==n || 0==n) return 1; else return n*get_factorial(n-1); } /*给定元素个数n,以及数组p,返回全排列的序号*/ template<typename T> int perm2num(int n, T *p){ int i, j, num=0,k=1; for (i=n-2;i>=0;i--)//注意下标从0开始 { for (j=i+1;j<n;j++) if (p[j]<p[i]) num+=k;//是否有逆序,如有,统计 k*=n-i; //每一轮后k=(n-i)!, } return num; } /*BFS(字典序)*/ template<typename T> void bfs_permute(T array[], int size) { int idx=0; int cnt=get_factorial(size); list<T> ls; queue<list<T>> q; ls.push_back(array[0]); q.push(ls); while(!q.empty()) { list<T> cur_perm = q.front(); if(cur_perm.size() == size) //第n层的第一个元素长度等于size,循环结束 break; if(cur_perm.size() != idx) //不相等 idx++; q.pop(); list<T>::iterator it = cur_perm.end(); while( it!=cur_perm.begin() ) { cur_perm.insert(it, array[idx]); //插入 q.push(cur_perm); it=cur_perm.erase(--it); //还原 --it; //向前一步找插入点 if( it==cur_perm.begin() ) //第一个插入点特殊处理并结束 { cur_perm.push_front(array[idx]); q.push(cur_perm); cur_perm.clear(); break; } } } print_queue(q, size, cnt); } template<typename T> void print_queue(queue<list<T>> q, int size, int cnt) { vector<list<T>> vec(cnt); T* perm=new T[size]; //存储当前排列 /*映射*/ while(!q.empty()) { list<T> cur_perm=q.front(); q.pop(); list<T>::iterator it=cur_perm.begin(); int idx=0,i=0; int n=size; while(it!=cur_perm.end()) { perm[i++]=*it++; } //当前排列放入全排列对应位置 idx=perm2num(size, perm); vec[idx]=cur_perm; } delete []perm; /*输出*/ vector<list<T>>::iterator vit=vec.begin(); for(;vit!=vec.end();vit++) { list<T> cur_perm=*vit; list<T>::iterator lit=cur_perm.begin(); for(;lit!=cur_perm.end();lit++) { cout<<*lit<<" "; } cout<<endl; } } int main(){ recur_permute(array, 0, 3); lexi_recur_permute(array, 0,3); stl_permute(array, 4); bfs_permute(array, 4); return 0; }
    复制代码

     

    上面一共提供了4种全排列的方法,包括递归非字典序版本、递归字典序版本、标准库版本和BFS字典序版本,当然BFS非字典序实现相对于BFS字典序版本更加简洁,稍加修改即可。

    说明:递归版本基于网上现有代码修改而成,标准库版本参照msdn sample修改而成,最后的BFS版本是由本人在看到题目后思考而来,并实现之(递归版本很久之前写过),所有四种算法都加了模板。当然BFS版本效率相对于递归要快,相对于STL版本则较慢,仅仅提供一种思路而已

     

    最后再附上STL版本算法思路及修改后的代码(仅仅为了可读性):

     

    思路

    给定已知序列P =  A1A2A3.....An
    对P按字典排序,得到P的一个最小排列Pmin = A1A2A3....An ,满足Ai > A(i-1) (1 < i <= n)
    从Pmin开始,找到刚好比Pmin大的一个排列P(min+1),再找到刚好比P(min+1)大的一个排列,如此重复。
    1.从后向前(即从An->A1),找到第一对为升序的相邻元素,即Ai < A(i+1)。
      若找不到这样的Ai,说明已经找到最后一个全排列,可以返回了。
    2.从后向前,找到第一个比Ai大的数Aj,交换Ai和Aj。
    3.将排列中A(i+1)A(i+2)....An这个序列的数逆序倒置,即An.....A(i+2)A(i+1)。因为由前面第1、2可以得知,A(i+1)>=A(i+2)>=.....>=An,这为一个升序序列,应将该序列逆序倒置,所得到的新排列才刚刚好比上个排列大。
    4.重复步骤1-3,直到返回。
    这个算法是C++ STL算法next_permutation的思想。
     
    代码
    复制代码
  • 相关阅读:
    【故障处理】ORA-12162: TNS:net service name is incorrectly specified (转)
    android studio 编程中用到的快捷键
    java时间格式串
    android Error occurred during initialization of VM Could not reserve enough space for object heap Could not create the Java virtual machine.
    linux安装vmware
    x1c 2017 安装mint18的坑——grub2
    x1c2017 8G版 win linux的取舍纠结记录
    python的try finally (还真不简单)
    kafka+docker+python
    json文件不能有注释
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3346781.html
Copyright © 2011-2022 走看看