全排列的非递归实现
算法描述
实现全排列的非递归的排列,首先我们要明确排列的顺序,这样我们才会不会漏掉任何一个排列,我们按照从小到大的顺序排列,例如:“1234”的下一个就是“1243”,在下一个就是“1324”……
- 首先,对于给定数列,如果不是一个最小数,如1324,则将它转换为最小数,我们先对它进行排序,保证该数列是所有数字组合数列中值最小,可以用快排,或则库函数qsort(s , n , sizeof(s[0]) , cmp)(第三个参数是一个函数指针)
int cmp(const void * a, const void * b)
{
return ( (int)a - (int)b );
}
这里我们复习一下快排
#include<stdlib.h>
#include<stdio.h>
int RandomInRange(int start,int end)
{
int index = rand()%end;
return index;
}
void swap(int* p,int* q)
{
int ptemp = *p;
*p = *q;
*q = ptemp;
}
int Paration(int data[],int length,int start,int end)
{
if(data==NULL || length<=0 || start<0 || end>=length)
return 0;
int index = RandomInRange(start,end);//产生一个在[strat,end]之间的一个随机数
swap(&data[index],&data[end]);//将下标为end的值与下标为index的值交换
int small = start-1;
for(index=start; index<end; ++index)
{
if(data[index]<data[end])//分界值data[end],小于该值放在数组前面
{
++small;
if(small!=index)
swap(&data[index],&data[small]);
}
}
++small;
swap(&data[small],&data[end]);
return small;
}
void QuickSort(int data[],int length,int start,int end)
{
if(start == end)
return;
int index = Paration(data,length,start,end);
if(index>start)
QuickSort(data,length,start,index-1);
if(index<start)
QuickSort(data,length,index+1,end);
}
int main()
{
int data[] = {3,4,5,2,1};
QuickSort(data,5,0,4);
getchar();
return 0;
}
如何计算字符串的下一个排列了?来考虑”926520”这个字符串,我们从后向前找第一双相邻的递增数字,”20”、”52”都是非递增的,”26 “即满足要求,称前一个数字2为替换数,替换数的下标称为替换点,再从后面找一个比替换数大的最小数(这个数必然存在),0、2都不行,5可以,将5和2交换得到”956220”,然后再将替换点后的字符串”6220”颠倒即得到”950226”。
如果达到这个数的最大,比如“1234”到”4321“,这个时候就结束整个循环。
2.算法实现
#include<stdio.h>
#include<iostream>
using namespace std;
void Reverse(int* array,int begin,int end)
{
if(array == NULL||end-begin<=0)
return;
int* pbegin = array+begin;
int* pend = array+end;
while(pbegin < pend)
{
swap(*pbegin,*pend);
pbegin++;
pend--;
}
}
void Print(int* array,size_t size)
{
for(size_t idx=0; idx<size; ++idx)
cout<<array[idx]<<" ";
printf("\n");
}
bool IsEnd(int* ptemp,int* array,size_t size)//判断循环是否要结束,当循环出现最大数列时结束例如1234---4321时结束
{
for(size_t i=0,j=size-1; i<size,j>=0; ++i,--j)
{
if(ptemp[j] != array[i])//若array数列不是最大值,则继续排列
return false;
}
return true;
}
void Perm(int* array,int size,int N)
{
int* temparray = new int[size];//临时数组,用于判断是否继续排列
memset(temparray,0,sizeof(int)*size);
for(size_t idx=0;idx<size;idx++)
{
temparray[idx] = array[idx];
}
int replace;//选择要替换的数的下标(从后向前遍历,该位置的值要比后面一个位置的值小)
int charg;//与要替换的数交换的数的下标(该数是从替换的数到最后一个数中比要替换数大的最小数)
Print(array,size);//打印原数列
while(!IsEnd(temparray,array,size))
{
for(size_t idx=size-1; idx>=N+1; --idx)
{
if(array[idx] > array[idx-1])//寻找replace
{
replace = idx-1;
for(size_t i=size-1; i>=replace+1; --i)//寻找charg;
{
if(array[i]>array[replace])
{
charg = i;//因为数列是已经排序的,由小到大,所以替换数的后面一定有比该替换数大的最小值
break; //而且替换数后面的数一定是递减的,从后往前第一个比替换数大的数就是我们要找的交换数
}
}
swap(array[charg],array[replace]);
Reverse(array,replace+1,size-1);//都用下标表示
Print(array,size);
continue;
}
}
}
delete[] temparray;
}
int main()
{
int array[]= {1,2,3,4};
Perm(array,4,1);
getchar();
return 0;
}