在高级语言中,函数的参数传递是由栈来实现的,后调用的函数的参数在栈的上部,先调用的函数的参数在栈的下部,在实现递归函数时,每一次调用的参数等信息都会保存在栈中,这样在数据比较在时会出现栈溢出的错误,而且反复调用函数,会使效率变的较低,在VC中对10万个数排序,用递归的快排花了30ms,而用非递归,需要25ms。
而我们可以很容易的通过使用自定义的栈,来将其转化为全部在一个函数中实现,而无需进行递归函数调用,从而节省了大量时间,而且也可以尽量避免栈举出的问题。
递归函数一般有两类,一类是先执行函数操作,再递归调用函数自身,一类是先递归调用自身,再执行函数操作,题目所述的两种排序分别属于两种递归调用。
先说快速排序,首先将它的递归版本给出,每次以最后一个元素为标准,将比它小的元素全部换到前面去,然后把最后一个元素换到最后一个比它小的元素后面,从而实现该元素左面的元素都比它小,而右面的都比它大:
void ksort(int l,int h,int a[])//l为第一个元素下标 h为最后一个元素下标的后一个
{
int i,j=l;
int tem;
if(l>=h)return;
for(i=l;i<h-1;i++)/一次遍历,将比a[h-1]小的元素都搬到左面,j表示下一次需要交换的/元素的位置
{
if(a[i]<a[h-1])如果比a[h-1]小,就搬到左面去
{
tem=a[i];
a[i]=a[j];
a[j]=tem;
j++;
}
}
tem=a[j];//最后将a[h-1]搬到中间去,让不比它小的都在它右面
a[j]=a[h-1];
a[h-1]=tem;
ksort(l,j,a);///递归
ksort(j+1,h,a);
}
要模拟该递归过程 , 首先要做的就是建立一个栈 , 最简单的方法是用数组 , 建立两个数组模拟的栈 sl[100],sh[100] 分别存放 参数中的每次操作的首元素的位置和尾元素的后一个位置 ,定义变量head表示栈顶指针,
首先将sl[0] 和 sh[0] 分别赋值为 l 和 h , 对于先执行后递归的函数,在每次执行递归的时候 , 将新的参数压入栈中, 然后在入栈之后重新执行新一轮的函数操作, 因为重复执行同样的动作, 所以需要一个循环 ,每个取参数, head 要自减, 所以跳出条件就是head<0:
while(head>=0)
{
x=sl[head];
y=sh[head];
head--;
j=x;
for(i=x;i<y-1;i++)
{
if(a[i]<a[y-1])
{
tem=a[i];
a[i]=a[j];
a[j]=tem;
j++;
}
}
tem=a[j];
a[j]=a[y-1];
a[y-1]=tem;
if(x<j)
{
head++;
sl[head]=x;
sh[head]=j;
}
if(j+1<y)
{
head++;
sl[head]=j+1;
sh[head]=y;
}
}
}
类似快速排序这类递归调用的特点是取一次参数执行一次操作,之后这组参数就没有用了,可以被下一组参数所覆盖了,从而不需要很将所有的参数都保存在栈中,再集中进行处理,而归并排序这样的先递归,后操作的,则不可以了,下面是归并排序的递归版代码:
void mergesort(int a[],int l,int h)///此中的h为最后一个元素的位置
{
if(l>=h)return ;
int m=(l+h)/2;
mergesort(a,l,m);
mergesort(a,m+1,h);经过这两行,l到m和m=1到h,就都是已经有序的序列了,然后//将两个有序序列进行归并
int *arr=new int[h-l+1];
int k=0;
int i=l,j=m+1;
while(i<=m&&j<=h)
{
if(a[i]<a[j])
{
arr[k]=a[i];
i++;
k++;
}
else
{
arr[k]=a[j];
j++;
k++;
}
}
if(i<=m)
{
while(i<=m)
{
arr[k]=a[i];
i++;k++;
}
}
if(j<=h)
{
while(j<=h)
{
arr[k]=a[j];
j++;k++;
}
}
for(i=l;i<=h;i++)
{
a[i]=arr[i-l];
}
delete[]arr;
}
可见,它需要先进行递归,条件成立的话,继续递归,直到条件不成立,则返回,最后一层递归调用的函数返回之后才会执行下面归并的操作,所以要先将所有归并操作中要用到的参数都保存起来,最后再一层一层进行归并,保存参数的过程即为将所有的参数入栈,
而每次新入栈的参数决定于之前的参数,因为归并排序是分治解决问题的
while(head1<=head)head1表示用来决定新参数的参数在栈中的位置,head为新参数的///位置
{
x=sl[head1];
y=sh[head1];
head1++;
m=(x+y)/2;
if(x<m)
{
head++;
sl[head]=x;
sh[head]=m;
}
if(m+1<y)
{
head++;
sl[head]=m+1;
sh[head]=y;
}
}
栈建好之后,就可以在栈中从顶至底取参数,进行归并了
while(head>=0)
{
x=sl[head];
y=sh[head];
head--;
m=(x+y)/2;
int *arr=new int[y-x+1];
i=x,j=m+1,k=0;
while(i<=m&&j<=y)
{
if(a[i]<a[j])
{
arr[k]=a[i];
i++;
k++;
}
else
{
arr[k]=a[j];
j++;
k++;
}
}
if(i<=m)
{
while(i<=m)
{
arr[k]=a[i];
i++;k++;
}
}
if(j<=y)
{
while(j<=y)
{
arr[k]=a[j];
k++;j++;
}
}
for(i=x;i<=y;i++)
{
a[i]=arr[i-x];
}
delete[]arr;
}
}
以上为个人学习总结, 欢迎reader们提出宝贵建议与指导~