目录
每一次递归,都会在栈上开辟一块新的空间,如果递归的次数过多,在栈上开辟的空间过多,就会发生栈溢出,这是所有程序都要极力避免的,所以如果有使用递归实现的算法,都尽量改成非递归的算法,就能避免栈溢出.
# 1.快速排序的递归版本
快速排序有三种算法:霍尔法、挖坑法、双指针法
代码如下:
// 快速排序hoare版本
int PartSort1(int* a, int left, int right)
{
int keyi = left;
while (left < right)
{
while (a[right] >= a[keyi] && left < right)
{
right--;
}
while (a[left] <= a[keyi] && left < right)
{
left++;
}
swap(&a[left], &a[right]);
}
swap(&a[keyi], &a[left]);
return left;
}
//挖坑法
int PartSort2(int* a, int left, int right)
{
int keyi = left;
int key = a[left];
while (left < right)
{
while (a[right] >= key && left < right)
{
right--;
}
a[left] = a[right];
while (a[left] <= key && left < right)
{
left++;
}
a[right] = a[left];
}
a[right] = key;
return right;
}
// 快速排序前后指针法
int PartSort3(int* a, int left, int right)
{
int key = a[left];
int cur = left + 1;
int prev = left;
while (cur <= right)
{
if (a[cur] < key && ++prev!= cur)
{
swap(&a[prev], &a[cur]);
}
cur++;
}
swap(&a[left], &a[prev]);
return prev;
}
void QuickSort(int* a, int left, int right)
{
if (left >= right)
return;
if (right - left < 200)
{
InsertSort(a+left, right-left+1);
return;
}
// 随机选key
int randi = left + (rand() % (right - left+1));
swap(&a[left], &a[randi]);
//三数取中
//int midi = GetMidNumi(a, left, right);
//swap(&a[midi], &a[left]);
int keyi = PartSort2(a, left, right);
// 递归
QuickSort(a, left, keyi - 1);
QuickSort(a, keyi + 1, right);
}
# 2.递归创建栈帧,储存了那些东西?
我们看快速排序的函数类型:void QuickSort(int* a, int left, int right);可得知每一次创建栈帧都有三个变量:a,left和right.而a是一直不变的,所以如果考虑非递归版本,我们可以用一个数据结构把left和right存起来,这里我用栈结构存储所有的left和right;
# 3.快速排序的非递归版本
思路:首先把要排的left和right压栈,然后进入循环,弹出left和right,找到key,然后把左区间和右区间的left和right压栈,这里要注意,如果左区间或右区间只有一个元素了,该区间的left和right就不需要压栈了,因为就一个元素不需要排序了.下一个问题是什么时候结束循环?不难发现当栈为空的时候,就说明已经没有left到right的区间需要排序了,也就是说已经排好序了,所以进入循环的条件是栈不为空.以下是代码;
// 快速排序 非递归实现
void QuickSortNonR(int* a, int left, int right)
{
Stack stack;
StackInit(&stack);
StackPush(&stack, right);
StackPush(&stack, left);
while (!StackEmpty(&stack))
{
left = StackTop(&stack);
StackPop(&stack);
right = StackTop(&stack);
StackPop(&stack);
if (right - left < 200)
{
InsertSort(a + left, right - left + 1);
continue;
}
// 随机选key
int randi = left + (rand() % (right - left + 1));
swap(&a[left], &a[randi]);
int keyi = PartSort2(a, left, right);
if (keyi + 1 < right)
{
StackPush(&stack, right);
StackPush(&stack, keyi + 1);
}
if (left < keyi - 1)
{
StackPush(&stack, keyi - 1);
StackPush(&stack, left);
}
}
StackDestroy(&stack);
}
以上就是所有内容,如有错误欢迎指出!