问题来自《Linux C一站式编程》,是个挺有意思的题目。

2、定义一个数组,编程打印它的全排列。比如定义:

#define N 3
int a[N] = { 1, 2, 3 };

则运行结果是:

$ ./a.out
1 2 3
1 3 2
2 1 3
2 3 1
3 2 1
3 1 2

程序的主要思路是:

  1. 把第1个数换到最前面来(本来就在最前面),准备打印1xx,再对后两个数2和3做全排列。
  2. 把第2个数换到最前面来,准备打印2xx,再对后两个数1和3做全排列。
  3. 把第3个数换到最前面来,准备打印3xx,再对后两个数1和2做全排列。

可见这是一个递归的过程,把对整个序列做全排列的问题归结为对它的子序列做全排列的问题,注意我没有描述Base Case怎么处理,你需要自己想。
你的程序要具有通用性,如果改变了N和数组a的定义(比如改成4个数的数组),其它代码不需要修改就可以做4个数的全排列(共24种排列)。

完成了上述要求之后再考虑第二个问题:如果再定义一个常量M表示从N个数中取几个数做排列(N==M时表示全排列),原来的程序应该怎么改?

最后再考虑第三个问题:如果要求从N个数中取M个数做组合而不是做排列,就不能用原来的递归过程了,想想组合的递归过程应该怎么描述,编程实现它。

不考虑数组元素相同的情况,我们可以按照题目提供的思路写出如下代码:

#include <stdio.h>
#define N 3 int a[N]; void perm(int); /*求数组的全排列 */
void print();
void swap(int, int); int main(){
int i;
for(i = ; i < N; ++i){
a[i] = i + ;
}
perm();
} void perm(int offset){
int i, temp;
if(offset == N-){ // BaseCase
print();
return;
}else{
for(i = offset;i < N; ++i){
swap(i, offset);//交换前缀
perm(offset + );//递归
swap(i, offset);//将前缀换回来,继续做前一次排列
}
}
} void print(){
int i;
for(i = ; i < N; ++i)
printf(" %d ",a[i]);
printf("\n");
} void swap(int i, int offset){
int temp;
temp = a[offset];
a[offset] = a[i];
a[i] = temp;
}

如果平常递归写的不多的话,这段代码还是很容易写错的(没错,我就是在说我自己)。
在perm函数递归调用自己之后记得把元素位置交换回去,保证回溯时条件一致。

然后看第二个问题,这是更加一般的排列。仔细观察上面的代码,把特殊推导到一般,主要修改如下(用注释符标出):

#include <stdio.h>
#define N 4
#define M 2 // 取出M个元素进行排列,默认M<=N void print(){
int i;
for(i = ; i < M; ++i) // N->M,打印a里前M个排列元素
printf(" %d ",a[i]);
printf("\n");
} void perm(int offset){
int i;
if(offset == M){ // N->M,排列到M个数时递归到达BaseCase
print();
return;
}else{
for(i = offset;i < N; ++i){
swap(i, offset);
perm(offset + );
swap(i, offset);
}
}
}

再来看组合,同样用要求用递归解决,如果相关概念没有搞得很清楚,加上上面写的排列的代码,很容易写不出来(没错,说的还是我),然而代码其实很简单,不过递归确实更加复杂。

void comb(int n, int m)
{
int i;
if (m == ) {
print();
return;
} else {
for (int i = n-; i >= ; --i)
{
b[m-] = a[i];
comb(i, m-);
}
}
}

复杂之处在于,排列都是(n->n-1)这样的递归,然而组合这里是(n->i,m->m-1)这样非规律的递归调用,因为i是个变量。
但是组合的算法描述很简单,假设有一个两两元素互不相同的N长数组a,从数组尾端依次取M个数(b1,b2,···,bm)成为一个组合,并且满足条件:如果i>j,那么bi在a中的下标一定小于bj。

简单来说,就是从后往前取数组里的M个数,只有保持这样的偏序关系才能保证不会重复组合。

如何用C表示排列组合?的更多相关文章

  1. 学习sql中的排列组合,在园子里搜着看于是。。。

    学习sql中的排列组合,在园子里搜着看,看到篇文章,于是自己(新手)用了最最原始的sql去写出来: --需求----B, C, F, M and S住在一座房子的不同楼层.--B 不住顶层.C 不住底 ...

  2. .NET平台开源项目速览(11)KwCombinatorics排列组合使用案例(1)

    今年上半年,我在KwCombinatorics系列文章中,重点介绍了KwCombinatorics组件的使用情况,其实这个组件我5年前就开始用了,非常方便,麻雀虽小五脏俱全.所以一直非常喜欢,才写了几 ...

  3. 【原创】开源.NET排列组合组件KwCombinatorics使用(三)——笛卡尔积组合

           本博客所有文章分类的总目录:本博客博文总目录-实时更新 本博客其他.NET开源项目文章目录:[目录]本博客其他.NET开源项目文章目录 KwCombinatorics组件文章目录: 1. ...

  4. 【原创】开源.NET排列组合组件KwCombinatorics使用(二)——排列生成

           本博客所有文章分类的总目录:本博客博文总目录-实时更新 本博客其他.NET开源项目文章目录:[目录]本博客其他.NET开源项目文章目录 KwCombinatorics组件文章目录: 1. ...

  5. 【原创】开源.NET排列组合组件KwCombinatorics使用(一)—组合生成

           本博客所有文章分类的总目录:本博客博文总目录-实时更新 本博客其他.NET开源项目文章目录:[目录]本博客其他.NET开源项目文章目录 KwCombinatorics组件文章目录: 1. ...

  6. hdu1521 排列组合(指数型母函数)

    题意: 有n种物品,并且知道每种物品的数量ki.要求从中选出m件物品的排数.         (全题文末) 知识点: 普通母函数 指数型母函数:(用来求解多重集的排列问题) n个元素,其中a1,a2, ...

  7. [leetcode] 题型整理之排列组合

    一般用dfs来做 最简单的一种: 17. Letter Combinations of a Phone Number Given a digit string, return all possible ...

  8. 排列组合算法(PHP)

    用php实现的排列组合算法.使用递归算法,效率低,胜在简单易懂.可对付元素不多的情况. //从$input数组中取$m个数的组合算法 function comb($input, $m) { if($m ...

  9. iOS多线程中,队列和执行的排列组合结果分析

    本文是对以往学习的多线程中知识点的一个整理. 多线程中的队列有:串行队列,并发队列,全局队列,主队列. 执行的方法有:同步执行和异步执行.那么两两一组合会有哪些注意事项呢? 如果不是在董铂然博客园看到 ...

随机推荐

  1. StringReplace用法

    来自:http://www.aspww.cn/View/12022801.aspx ---------------------------------------------------------- ...

  2. Spring MVC BeanNameUrlHandlerMapping example

    In Spring MVC, BeanNameUrlHandlerMapping is the default handler mapping mechanism, which maps URL re ...

  3. Spring AOP Interceptor transaction is not working

    Problem The Spring AOP transaction is not working in following interceptors? <bean id="testA ...

  4. poj 1517 u Calculate e

    u Calculate e Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 19465   Accepted: 11362   ...

  5. SQL Select count(*)和Count(1)的区别和执行方式及SQL性能优化

    SQL性能优化:http://www.cnblogs.com/CareySon/category/360333.html Select count(*)和Count(1)的区别和执行方式 在SQL S ...

  6. IEBrowse学习笔记

    //登录 private void toolStripButton1_Click(object sender, EventArgs e) { //ie.ExecuteScript("aler ...

  7. java 分页

    ListAction.java package com.sy.action; import java.util.List; import com.opensymphony.xwork2.ActionS ...

  8. windows服务控制类

    /// <summary> /// 服务调用控制 /// </summary> public class WinServiceController { /// <summ ...

  9. 预览Cube出现没有注册类错误

    用Microsoft SQL Server Management Studio预览AS上的Cube 出现如下错误. TITLE: Microsoft SQL Server Management Stu ...

  10. Flex友好提示、警告

    Flex 自带的Alert带给用户的体验并不好,对于一些简单的提示来说,这个小题大作了. <?xml version="1.0" encoding="utf-8&q ...