生成排列算法

1、递归方法

例如,如果集合是{1,2,3},那么这个集合中元素的所有排列是{(1,2,3),(1,3,2),(2,1,3),(2,3,1),(3,1,2),(3,2,1)},显然,给定n个元素共有n!种不同的排列,如果给定集合是{1,2,3,4},可以用下面给出的简单算法产生其所有排列,即集合(1,2,3,4)的所有排列有下面的排列组成:

(1)以1开头后面跟着(2,3,4)的排列

(2)以2开头后面跟着(1,3,4)的排列

(3)以3开头后面跟着1,2,4)的排列

(4)以4开头后面跟着(1,2,3)的排列,这显然是一种递归的思路,于是我们得到了以下的实现:

void swap(int &a,int &b)
{
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}
void permutation(int* a,int k,int m)
{
     int i,j;
     if(k == m)
     {
         for(i=0;i<m;++i)
             cout << a[i];
         cout<<endl;
     }
     else
     {
         for(j=k;j<m;++j)
        {
             swap(&a[k],&a[j]);
             permutation(a,k+1,m);
             swap(&a[k],&a[j]);
        }
     }
}         

去掉重复符号的全排列:在交换之前可以先判断两个符号是否相同,不相同才交换,这个时候需要一个判断符号是否相同的函数。

void swap(int &a,int &b)
{
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
}

bool isSwap(int *a ,int begin,int end)
{
    for(int i=begin;i<end;++i)
    {
          if(a[i] == a[end])
              return false;
    }
    return true;
}

void permutation(int* a,int k,int m)
{
     int i,j;
     if(k == m)
     {
         for(i=0;i<m;++i)
             cout << a[i];
         cout<<endl;
     }
     else
     {
         for(j=k;j<m;++j)
        {
             if(isSwap(a,k,j))     // 去掉重复元素
            {
                 swap(&a[k],&a[j]);
                 permutation(a,k+1,m);
                 swap(&a[k],&a[j]);
            }
        }
     }
}     

2、非递归实现

基本思想是:
    1.对初始队列进行排序,找到所有排列中最小的一个排列Pmin。
    2.找到刚刚好比Pmin大比其它都小的排列P(min+1)。
    3.循环执行第二步,直到找到一个最大的排列,算法结束。
如排列ABCDE,这是所有排列中最小的一个排列,刚好比ABCDE大的排列是:ABCED。
算法如下:
给定已知序列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,直到返回。

void swap(int *a,int i,int j)
{
    a[i]^=a[j];
    a[j]^=a[i];
    a[i]^=a[j];
}  

//将数组a中的下标i到下标j之间的所有元素逆序倒置
void reverse(int a[],int i,int j)
{
    for(; i<j; ++i,--j) {
        swap(a,i,j);
    }
}  

void print(int a[],int length)
{
    for(int i=0; i<length; ++i)
        cout<<a[i]<<ends;
    cout<<endl;
}  

//求取全排列,打印结果
void combination(int a[],int length)
{
    if(length<2) return;  

    bool end=false;
    while(true) {
        print(a,length);  

        int i,j;
        //找到不符合趋势的元素的下标i
        for(i=length-2; i>=0; --i) {
            if(a[i]<a[i+1]) break;
            else if(i==0) return;
        }  

        for(j=length-1; j>i; --j) {
            if(a[j]>a[i]) break;
        }  

        swap(a,i,j);
        reverse(a,i+1,length-1);
    }
}  
时间: 2024-10-12 03:04:00

生成排列算法的相关文章

算法笔记03--归纳法之生成排列

生成排列 生成排列即对n个数的全排列,显然时间复杂度是n指数级的O(n^k) 假定可以生成n-1个数的所有排列,那么就可以扩展生成1,2,.....,n的排列. 例如1的生成排列即1 1,2的生成排列即1,2和2,1 1,2,3的生成排列在1,2的生成排列基础上可以这样得到: 1在第1位,2,3的生成排列 2在第1位,1,3的生成排列 3在第1位,2,3的生成排列 那么推广到1,2,...,n的生成排列即: 1在第1位,2,...,n的生成排列 2在第2位,1,3,...n的生成排列 ....

减一技术应用:生成排列与幂集(Java实现)

减一技术,与二分搜索一样,是一种通用算法设计技术.它是分治法的一种特殊形式,通过建立问题实例P(n) 与问题实例P(n-1)的递推求解关系式而实现:最经典的例子莫过于插入排序了.这里,给出减一技术在生成排列组合方面的应用. (一)  排列问题: 生成自然数 1,2,,,,,n 的所有排列. 算法描述: 使用减一技术,建立自然数12...n的排列与12...n-1的递推关系.假设 P(n-1) 是 自然数 12...n-1的所有排列 p1, p2,..., p(m)的集合,则P(n)通过如下方式得

Stanford大学机器学习公开课(五):生成学习算法、高斯判别、朴素贝叶斯

(一)生成学习算法 在线性回归和Logistic回归这种类型的学习算法中我们探讨的模型都是p(y|x;θ),即给定x的情况探讨y的条件概率分布.如二分类问题,不管是感知器算法还是逻辑回归算法,都是在解空间中寻找一条直线从而把两种类别的样例分开,对于新的样例,只要判断在直线的哪一侧即可:这种直接对问题求解的方法可以称为判别学习方法. 而生成学习算法则是对两个类别分别进行建模,用新的样例去匹配两个模板,匹配度较高的作为新样例的类别,比如分辨大象(y=1)和狗(y=0),首先,观察大象,然后建立一个大

生成学习算法(Generative Learning algorithms)

一:引言 在前面我们谈论到的算法都是在给定x的情况下直接对p(y|x;Θ)进行建模.例如,逻辑回归利用hθ(x) = g(θTx)对p(y|x;Θ)建模. 现在考虑这样一个分类问题,我们想根据一些特征来区别动物是大象(y=1)还是狗(y=0).给定了这样一个训练集,逻辑回归或感知机算法要做的就是去找到一个决策边界,将大象和狗的样本分开来.但是如果换个思路,首先根据大象的特征来学习出一个大象的模型,然后根据狗的特征学习出狗的模型,最后对于一个新的样本,提取它的特征先放到大象的模型中求得是大象的概率

【cs229-Lecture5】生成学习算法:1)高斯判别分析(GDA);2)朴素贝叶斯(NB)

参考: cs229讲义 机器学习(一):生成学习算法Generative Learning algorithms:http://www.cnblogs.com/zjgtan/archive/2013/06/08/3127490.html 首先,简单比较一下前几节课讲的判别学习算法(Discriminative Learning Algorithm)和本节课讲的生成学习算法(Generative Learning Algorithm)的区别. eg:问题:Consider a classi?cat

生成学习算法、朴素Bayes入门

PART0  判别学习算法 引入:二元分类问题 建模:判别学习算法(discriminative learning algorithm)直接根据P(y|x)[即给定特征x下的分类结果y]建模 之前我们用的算法(如logistic回归)就是判别学习算法 PART1  生成学习算法 PART1.1  Definition 引入:还是二元分类问题 建模:生成学习算法(generative learning algorithm)对P(x|y)[即给定具体的一类y下的特征x].P(y)建模,然后由baye

HDU 4771 Stealing Harry Potter&#39;s Precious (生成排列+枚举 + BFS)

Stealing Harry Potter's Precious Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1982    Accepted Submission(s): 931 Problem Description Harry Potter has some precious. For example, his invisib

机器学习算法笔记2_1:生成学习算法(Generative Learning algorithms)

我们之前学习的算法都是基于p(y|x;θ), 他的思想是找出找出一个决策边界来将两类分开,而生成算法是先对两个类别分别建模,为了将样本分开,将样本代入两个模型,看样本与哪个类别更匹配. 这种试图直接从输入x映射到类别标签{0,1}的算法被称为判别学习算法:而通过计算p(x|y)(和p(y))来得到模型的算法被称为生成学习算法 通过贝叶斯函数得到p(y|x)=p(x|y)p(y)p(x), argmaxyp(y|x)=argmaxyp(x|y)p(y)p(x)=argmaxyp(x|y)p(x)

Stanford机器学习[第五讲]-生成学习算法

本课内容: 生成学习算法的介绍: 第一个典型的生成学习算法--高斯判别分析: 生成学习算法与之前的判别学习算法的对比: 朴素贝叶斯算法, Laplace平滑. 1.生成学习算法 学习算法分为两种:一种是判别学习算法(Discriminative Learning Algorithm),简称DLA,另一种是生成学习算法(Generative Learning Algorithm),简称GLA. DLA通过建立输入空间X与输出标注{1, 0}间的映射关系学习得到p(y|x).而GLA首先确定p(x|