`

算法之排列组合算法

 
阅读更多

转自<http://dongxicheng.org/structure/permutation-combination/>

1. 前言

本文介绍了常用的排列组合算法,包括全排列算法,全组合算法,m个数选n个组合算法等。

2. 排列算法

常见的排列算法有:

(A)字典序法

(B)递增进位制数法

(C)递减进位制数法

(D)邻位对换法

(E)递归法

介绍常用的两种

(1) 字典序法

对给定的字符集中的字符规定了一个先后关系,在此基础上按照顺序依次产生每个排列。

[例]字符集{1,2,3},较小的数字较先,这样按字典序生成的全排列是:123,132,213,231,312,321。

生成给定全排列的下一个排列 所谓一个的下一个就是这一个与下一个之间没有字典顺序中相邻的字符串。这就要求这一个与下一个有尽可能长的共同前缀,也即变化限制在尽可能短的后缀上。

算法思想

设P是[1,n]的一个全排列。

P=P1P2…Pn=P1P2…Pj-1PjPj+1…Pk-1PkPk+1…Pn , j=max{i|Pi<Pi+1}, k=max{i|Pi>Pj} ,对换Pj,Pk,将Pj+1…Pk-1PjPk+1…Pn翻转, P’= P1P2…Pj-1PkPn…Pk+1PjPk-1…Pj+1即P的下一个

例子:839647521的下一个排列.

从最右开始,找到第一个比右边小的数字4(因为4<7,而7>5>2>1),再从最右开始,找到4右边比4大的数字5(因 为4>2>1而4<5),交换4、5,此时5右边为7421,倒置为1247,即得下一个排列:839651247.用此方法写出全排 列的非递归算法如下

该方法支持数据重复,且在C++ STL中被采用。

(2) 递归法

设一组数p = {r1, r2, r3, … ,rn}, 全排列为perm(p),pn = p – {rn}。则perm(p) = r1perm(p1), r2perm(p2), r3perm(p3), … , rnperm(pn)。当n = 1时perm(p} = r1。

如:求{1, 2, 3, 4, 5}的全排列

1、首先看最后两个数4, 5。 它们的全排列为4 5和5 4, 即以4开头的5的全排列和以5开头的4的全排列。

由于一个数的全排列就是其本身,从而得到以上结果。

2、再看后三个数3, 4, 5。它们的全排列为3 4 5、3 5 4、 4 3 5、 4 5 3、 5 3 4、 5 4 3 六组数。

即以3开头的和4,5的全排列的组合、以4开头的和3,5的全排列的组合和以5开头的和3,4的全排列的组合.

#include <stdio.h>
 
int n = 0;
 
void swap(int *a, int *b)
 
{
 
  int m;
 
  m = *a;
 
  *a = *b;
 
  *b = m;
 
}
 
void perm(int list[], int k, int m)
 
{
 
  int i;
 
  if(k > m)
 
  {
 
    for(i = 0; i <= m; i++)
 
      printf("%d ", list[i]);
 
    printf("\n");
 
    n++;
 
  }
 
  else
 
  {
 
    for(i = k; i <= m; i++)
 
    {
 
      swap(&list[k], &list[i]);
 
      perm(list, k + 1, m);
 
      swap(&list[k], &list[i]);
 
    }
 
  }
 
}
 
int main()
 
{
 
  int list[] = {1, 2, 3, 4, 5};
 
  perm(list, 0, 4);
 
  printf("total:%d\n", n);
 
  return 0;
 
}

 

 

3. 组合算法

3.1 全组合

在此介绍二进制转化法,即,将每个组合与一个二进制数对应起来,枚举二进制的同时,枚举每个组合。如字符串:abcde

00000 <– –> null

00001<– –> e

00010 <– –> d

… …

11111 <– –> abcde

3.2 从n中选m个数

(1) 递归

a. 首先从n个数中选取编号最大的数,然后在剩下的n-1个数里面选取m-1个数,直到从n-(m-1)个数中选取1个数为止。

b. 从n个数中选取编号次小的一个数,继续执行1步,直到当前可选编号最大的数为m。

下面是递归方法的实现:

/// 求从数组a[1..n]中任选m个元素的所有组合。
 
/// a[1..n]表示候选集,n为候选集大小,n>=m>0。
 
/// b[1..M]用来存储当前组合中的元素(这里存储的是元素下标),
 
/// 常量M表示满足条件的一个组合中元素的个数,M=m,这两个参数仅用来输出结果。
 
void combine( int a[], int n, int m,  int b[], const int M )
 
{
 
  for(int i=n; i>=m; i--)   // 注意这里的循环范围
 
  {
 
    b[m-1] = i - 1;
 
    if (m > 1)
 
      combine(a,i-1,m-1,b,M);
 
    else                     // m == 1, 输出一个组合
 
    {
 
      for(int j=M-1; j>=0; j--)
 
      cout << a[b[j]] << " ";
 
      cout << endl;
 
    }
 
  }
 
}
 

(2) 01转换法

本程序的思路是开一个数组,其下标表示1到n个数,数组元素的值为1表示其代表的数被选中,为0则没选中。

首先初始化,将数组前n个元素置1,表示第一个组合为前n个数。

然后从左到右扫描数组元素值的“10”组合,找到第一个“10”组合后将其变为“01”组合,同时将其左边的所有“1”全部移动到数组的最左端。

当第一个“1”移动到数组的n-m的位置,即n个“1”全部移动到最右端时,就得到了最后一个组合。

例如求5中选3的组合:

1 1 1 0 0 //1,2,3
 
1 1 0 1 0 //1,2,4
 
1 0 1 1 0 //1,3,4
 
0 1 1 1 0 //2,3,4
 
1 1 0 0 1 //1,2,5
 
1 0 1 0 1 //1,3,5
 
0 1 1 0 1 //2,3,5
 
1 0 0 1 1 //1,4,5
 
0 1 0 1 1 //2,4,5
 
0 0 1 1 1 //3,4,5
 

4. 参考资料

(1) http://www.cnblogs.com/nokiaguy/archive/2008/05/11/1191914.html

(2) http://comic.sjtu.edu.cn/thucs/GD_jsj_025y/text/chapter01/sec05/default.htm

(3) http://blog.csdn.net/sharpdew/archive/2006/05/25/755074.aspx

(4) http://xiaomage.blog.51cto.com/293990/74094

原创文章,转载请注明: 转载自董的博客

本文链接地址: http://dongxicheng.org/structure/permutation-combination/

作者:Dong,作者介绍:http://dongxicheng.org/about/

本博客的文章集合:

分享到:
评论

相关推荐

    基于c语言排列组合算法

    基于C语言排列组合算法 排列组合是计算机科学中一个重要的概念,它广泛应用于数学、统计学、计算机科学等领域。排列组合问题的算法设计是指如何高效地生成所有可能的排列或组合。今天,我们将讨论基于C语言的排列...

    C经典算法之排列组合

    ### C经典算法之排列组合 #### 知识点解析 **排列组合**是计算机科学与数学中的一个重要概念,广泛应用于密码学、数据处理、优化问题等领域。本篇内容主要介绍了如何利用C语言实现一个基本的排列算法。 #### 排列...

    C#实现排列组合算法完整实例

    在C#编程中,排列组合算法是解决许多数学和计算机科学问题的基础,特别是在处理数据排序、统计计算以及算法设计时。本实例详细介绍了如何利用C#实现这两种基本的算法:排列(Permutation)和组合(Combination)。...

    excel VBA - 排列组合生成算法 - 可指定和值 - 可输出文本文件.xls

    excel VBA - 排列组合生成算法 - ,可快速生成指定项目的所有排列组合

    PHP实现多种类型的排列组合算法

    总的来说,PHP虽然不是专门用于算法计算的语言,但通过巧妙的编程技巧和递归方法,可以有效地实现排列组合算法。以上代码示例展示了如何在PHP中实现这两种算法,通过学习和实践,开发者可以更好地理解和应用这些概念...

    组合数学之排列组合生成算法

    组合数学之排列组合生成算法,很好的学习组合排列算法的资料

    算法 排列组合生成器 后端

    这个项目为开发者提供了一个学习和实践排列组合算法、SpringBoot框架以及H2数据库整合的绝佳案例。它不仅展示了如何在后端实现复杂的算法,还涵盖了数据库管理和API设计等多个核心技能。对于希望提升后端开发能力的...

    基于c语言的排列组合算法

    在这个“基于C语言的排列组合算法”中,我们将深入探讨这两个概念以及如何使用C语言来实现它们。 排列是有限集合中的元素的一种有顺序的排列方式。在C语言中,我们可以使用递归方法来实现排列算法。首先,我们需要...

    c++ 排列组合算法,代码简单

    根据给定的文件信息,我们可以总结出以下关于C++中排列组合算法的知识点: ### C++中的排列组合算法实现 #### 1. 排列算法(Permutation) 在C++中,排列算法通常用于生成一组元素的所有可能顺序。在给定的代码中...

    排列组合算法实现

    排列组合算法实现,支持模板类。支持重复数的排列。算法采用递归方法,简单易懂。

    Java排列组合算法分析和代码实现

    总之,这个资源包提供了一个很好的平台,让你能够深入理解并实践Java中的排列组合算法。通过学习和理解这些代码,你不仅可以增强算法设计能力,还能提高解决实际编程问题的能力。记得动手实践,结合文档和代码,将...

    排列组合生成算法

    - 输入排列组合算法的代码,确保正确包含必要的头文件,如`#include &lt;iostream&gt;`,`#include &lt;algorithm&gt;`等。 - 使用`std::cout`打印结果,或者将结果保存到文件中。 - 编译并运行程序,观察输出结果。 4. **...

    qtc++排列组合实现

    在编程领域,排列组合是算法设计中的一个重要概念,它涉及到...通过以上方法,我们可以在Qt C++环境中高效地实现排列组合算法。无论是用于学术研究,还是解决实际的编程问题,掌握这些知识都将对你的编程生涯大有裨益。

    java排列组合算法

    在Java中实现排列组合算法可以帮助我们解决很多实际问题,比如数据排序、数据筛选等。下面将详细介绍排列和组合的基本概念以及在Java中的实现方法。 **排列** 是指从n个不同元素中取出m(m≤n)个元素,按照一定的...

    排列组合算法排列组合算法.doc

    在实际应用中,排列组合算法常常用于解决实际问题,如组合优化、数据分组、密码学等。例如,搜索引擎的搜索结果排序、推荐系统中的物品推荐、图论中的路径查找等,都可能涉及到排列组合的问题。熟练掌握这些算法对于...

    排列组合的全排列算法(交换算法)

    全排列算法是计算机科学中处理数组或集合的一种经典方法,主要应用于组合数学和算法设计领域。在本场景中,我们关注的是"交换算法",它用于生成一个给定数组的所有可能排列。全排列是指从n个不同元素中取出m个元素...

    Java排列组合算法 - 郭睿的专栏 - CSDN博客

    Java排列组合算法 - 郭睿的专栏 - CSDN博客Java排列组合算法 - 郭睿的专栏 - CSDN博客

    排列组合算法

    在编程领域,排列组合算法是解决许多问题的关键技术,尤其在数据处理、数据分析以及优化问题中扮演着重要角色。在C#编程环境下,利用这些算法可以有效地生成所有可能的序列或者选择,帮助开发者构建出高效的解决方案...

Global site tag (gtag.js) - Google Analytics