全排列

在程序设计过程中,我们往往要对一个序列进行全排列或者对每一个排列进行分析。           

全排列算法便是用于产生全排列或者逐个构造全排列的方法。当然,全排列算法不仅仅止于全排列,

对于普通的排列,或者组合的问题,也可以解决。

基本思想:解决一个算法问题,我比较习惯于从基本的想法做起,我们先回顾一下我们自己是如何

写一组数的全排列的:1,3,5,9(为了方便,下面我都用数进行全排列而不是字符)。 
1,3,5,9.(第一个) 首先保持第一个不变,对3,5,9进行全排列。 同样地,我们先保持3不变,对5,9进行全排列。 
保持5不变,对9对进行全排列,由于9只有一个,它的排列只有一种:9。接下来5不能以5打头了,5,9相互交换,

得到 1,3,9,5. 此时5,9的情况都写完了,不能以3打头了,得到 1,5,3,9 1,5,9,3 1,9,3,5 1,9,5,3 这样,

我们就得到了1开头的所有排列,这是我们一般的排列数生成的过程。再接着是以3、5、9打头,得到全排列。这里还要注意的一点是,

对于我们人而言,我们脑子里相当于是储存了一张表示原有数组的表,1,3,5,9,1开头的所有排列完成后,我们选择3开头,

3选完了之后,我们选择5开头,而不会再返过来选1,而且知道选到9之后结束,但对于计算机而言,我们得到了3,5,1,9后,

可能再次跳到1当中,因为原来数组的顺序它已经不知道了,这样便产生了错误。对于算法的设计,我们也可以维护这样一个数组,

它保存了原始的数据,这是一种方法。同时我们还可以再每次交换后再交换回来,变回原来的数组,这样程序在遍历的时候便不会出错。

读者可以练习一下这个过程,思考一下你是如何进行全排列的,当然,你的方法可能和我的不太一样。 
我们把上面全排列的方法归纳一下,基本上就是:任意选一个数(一般从小到大或者从左到右)打头,对后面的n-1个数进行全排列。

聪明的读者应该已经发现,这是一个递归的方法,因为要得到n-1个数的全排列,我们又要先去得到n-2个数的全排列,

而出口是只有1个数的全排列,因为它只有1种,为它的本身。写成比较规范的流程:

1.开始for循环。 
2.改变第一个元素为原始数组的第一个元素(什么都没做)。

3.求第2个元素到第n个元素的全排列。 
4.要求第2个元素到第n个元素的全排列,要递归的求第3个元素到第n个元素的全排列。 ...... 
5.直到递归到第n个元素到第n元素的全排列,递归出口。

6.将改变的数组变回。 

7.改变第一个元素为原始数组的第二个元素。 
(注:理论上来说第二次排列时才改变了第一个元素,即第6步应该此时才开始执行,但由于多执行一次无义的交换影响不大,

而这样使得算法没有特殊情况,更容易读懂,如果一定要省时间可以把这步写在此处,这种算法我在下文中便不给出了,读者可以自己写。)  

8.不断地改变第一个元素,直至n次使for循环中止。 

#include <stdio.h>
#include <stdlib.h>
void swap(int *n, int *m);
void permutation(int atr[], int start, int send);
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main() {
	int arr[] = {1, 2, 3};
	permutation(arr, 0, 3);
	return 0;
}

void permutation(int str[], int start, int send){
	int i, j;
	if(start >= send){
		for(i = 0; i < send; i++){
			printf("%d ", str[i]);
		}
		printf("\n");
	}
	else{
		for(i = start; i < send; i++){
			swap(&str[start], &str[i]);	
			permutation(str, start+1, send);
			swap(&str[start], &str[i]);	 
		}
	}
}

void swap(int *n, int *m){
	int tem = 0;
	
	tem = *n;
	*n = *m;
	*m = tem;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值