算法设计与分析:第二章 递归 2.7全排列

/*
排列问题:
有n个元素,编号为1,2,…,n,用一个具有n个元素的数组A来 存放所生成的排列,
然后输出它们。

自己分析:
关于全排列生成问题,刘汝佳介绍的算法的主体思路。
首先我们需要确定第一个数,这个数的选取是;遍历A[1]~A[n]
接下来如何选取第二个数,这是一个问题:
采用的方法是:判断当前位置上是不是已经有元素,如果没有就紧接着填充第2个元素
算法出口是:当标记变量为0的时候,那么n个元素全部填充完毕,此时输出所有组合

刘汝佳算法思想:
遍历所有的数,判断当前元素与前面元素不能重复,统计A[0]~A[iPos-1]中
当前待选取元素A[i]出现的次数c1,统计
A[0]~A[n-1]中A[i]出现的总次数c,如果c1<c是可以重复出现的
设置Per[pos] = A[i]并进行下面的递归

输入:
3
1 2 3
输出:
1 2 3
1 3 2
2 1 3
2 3 1 
3 1 2
3 2 1

*/

/*
关键:
1 遍历所有的数,判断当前元素与前面元素不能重复,统计A[0]~A[iPos-1]中
当前待选取元素A[i]出现的次数c1,统计
A[0]~A[n-1]中A[i]出现的总次数c,如果c1<c是可以重复出现的
设置Per[pos] = A[i]并进行下面的递归

2 	for(int i = 0 ; i < iLen ; i++)//对每个元素进行遍历尝试是否可以放入到最终数组中
	{
		if(!i || pArr[i] != pArr[i-1])//解决重复输出,这里采用或
		{
			int c1 = 0;
			for(int k = 0 ; k < iDepth ;k++)//统计在待插入元素在现有数组中出现的次数
			{
				if(pArr[i] == pPermutationArr[k])
				{
					c1++;
				}
			}
			int c = 0;
			for(int m = 0 ; m < iLen ;m++)//统计待插入元素在原始数组中出现的次数
			{
				if(pArr[i] == pArr[m])
				{
					c++;
				}
			}
			if(c1 < c)//如果还没有超出次数,则可以放入
			{
				pPermutationArr[iDepth] = pArr[i];
				dfs(pArr,iLen,pPermutationArr,iDepth+1);
3 void dfs(int* pArr,int iLen,int* pPermutationArr,int iDepth)

4 交换法思想	//对每个元素递归
	for(int i = iPos ; i < iLen ; i++)
	{
		//采用交换的方法:第一个元素与第二个元素交换
		int iTemp = pArr[i];
		pArr[i] = pArr[iPos];
		pArr[iPos] = iTemp;
		permutation(pArr,iLen,iPos+1);//继续递归从iPos后面继续进行交换
		//回溯
		iTemp = pArr[i];
		pArr[i] = pArr[iPos];
		pArr[iPos] = iTemp;
*/



#include <stdio.h>
#include <string.h>

const int MAXSIZE = 10000;
int g_visArr[MAXSIZE];

void dfs(int* pArr,int iLen,int* pPermutationArr,int iDepth)
{
	if(!pArr || iLen < 0)//鲁棒性
	{
		return ;
	}
	if(iDepth == iLen)//递归出口
	{
		for(int i = 0 ; i < iLen ; i++)
		{
			if(i)
			{
				printf(" %d",pPermutationArr[i]);
			}
			else
			{
				printf("%d",pPermutationArr[i]);
			}
		}
		printf("\n");
		return;//这里还需要返回
	}
	for(int i = 0 ; i < iLen ; i++)//对每个元素进行遍历尝试是否可以放入到最终数组中
	{
		if(!i || pArr[i] != pArr[i-1])//解决重复输出,这里采用或
		{
			int c1 = 0;
			for(int k = 0 ; k < iDepth ;k++)//统计在待插入元素在现有数组中出现的次数
			{
				if(pArr[i] == pPermutationArr[k])
				{
					c1++;
				}
			}
			int c = 0;
			for(int m = 0 ; m < iLen ;m++)//统计待插入元素在原始数组中出现的次数
			{
				if(pArr[i] == pArr[m])
				{
					c++;
				}
			}
			if(c1 < c)//如果还没有超出次数,则可以放入
			{
				pPermutationArr[iDepth] = pArr[i];
				dfs(pArr,iLen,pPermutationArr,iDepth+1);
			}
		}
	}
}

void permutation(int* pArr,int iLen,int iPos)
{
	if(iPos == iLen)
	{
		for(int i = 0 ; i < iLen ; i++)
		{
			if(i)
			{
				printf(" %d",pArr[i]);
			}
			else
			{
				printf("%d",pArr[i]);
			}
		}
		printf("\n");
		return;
	}

	//对每个元素递归
	for(int i = iPos ; i < iLen ; i++)
	{
		//采用交换的方法:第一个元素与第二个元素交换
		int iTemp = pArr[i];
		pArr[i] = pArr[iPos];
		pArr[iPos] = iTemp;
		permutation(pArr,iLen,iPos+1);//继续递归从iPos后面继续进行交换
		//回溯
		iTemp = pArr[i];
		pArr[i] = pArr[iPos];
		pArr[iPos] = iTemp;
	}
}

void process()
{
	int n;
	int iArr[MAXSIZE];
	int iPermutationArr[MAXSIZE];//用于存放生成的排列
	while(EOF != scanf("%d",&n))
	{
		if(n <= 0)
		{
			break;
		}
		for(int i = 0 ; i < n ; i++)
		{
			scanf("%d",&iArr[i]);
		}
		memset(g_visArr,0,sizeof(g_visArr));
		//dfs(iArr,n,iPermutationArr,0);
		//printf("\n");
		permutation(iArr,n,0);
	}
}

int main(int argc,char* argv[])
{
	process();
	getchar();
	return 0;
}

你可能感兴趣的:(算法设计与分析)