问题描述:
给定已知序列A1A2…An,求出其所有排列组合
一、递归算法
基本思路:
1. 如果n等于1,输出当前序列
2. 否则依次交换Ai(i=1,2..n-1,n)和An
3. 对于前n-1长度序列,重复1、2两步
算法复杂度O(n!),
算法缺点:如果序列中有重复字符,会出现相同排列组合。递归算法效率低。
算法优点:可以应用于所有字符串序列
二、非递归算法
基本思路:
1. 假设字符都是可比较的,每种排列组合之间都可以比较大小,A1A2…An的最小排列是P1P2…Pn(P1,p2..pn是非严格递增的)。
2. 从P1P2…Pn开始找出刚好比当前排列大的排列。
3. 循环第2步,直到得到最大的排列Pn…P2p1,算法结束。
如何找出刚好比当前排列大的,假设当前排列为B1B2…Bn,
1. 从最右开始,找到第一个递减的字符Bi,Bi<Bi+1,Bi+1>Bi+2>…>Bn,找不到就结束算法
2. 在Bn…Bi+1中找到第一个大于Bi的Bj,交换Bi和Bj,将Bi+1…Bn重新排序成递增排列,新的排列即为所求排列
3. 重复第1步
算法优点:不会出现重复排列组合
算法缺点:只能应用于可比较字符串,或需自定义比较函数
下面给出整数序列的算法代码,主要阐述思想
void Swap(int *a, int *b){ int tmp; tmp = *a; *a = *b; *b = tmp; } void AscSort(int *array, int n){ int i, j; for(i=n-1; i>=0; i--) for(j=0; j<i; j++) if(array[j]>array[j+1]) swap(&array[j], &array[j+1]); } void ArrayPrintf(int *array, int length){ int i; for(i=0; i<length; i++) printf("%d ",array[i]); printf(" "); } void NonRecurLoopArray(int *array, int length){ AscSort(array, length); ArrayPrintf(array,length); if(length<=1) return; while(true){ int i = length-1; int j = length-1; while(i>0 && array[i-1]>=array[i]) --i; if(i <= 0) return; while(j>i-1 && array[j]<=array[i-1]) j--; swap(&array[i-1], &array[j]); AscSort(&array[i], length-i); ArrayPrintf(array,length); } } void RecurLoopArray(int *array, int length, int num){ if(length==1){ ArrayPrintf(array, num); return; } for(int i=0; i<length; ++i){ swap(&array[i], &array[length-1]); RecurLoopArray(array, length-1, num); swap(&array[i], &array[length-1]); } }