个人主页:Yanni.—
数据结构:Data Structure.
C语言笔记:C Language Notes
OJ题分享: Topic Sharing
目录
前言:
非递归基础思想
快速排序非递归思路
快速排序非递归实现
归并排序的非递归思路
归并排序的非递归实现
在之前学习了快速排序和归并排序,但算法就是用递归实现的,在企业的面试中,很多企业不会问你快速排序和归并排序递归算法的思想,而是非递归实现这两个排序,今天为大家带来两个排序算法的非递归实现。
每个算法都有好有坏,递归算法的优势在于代码简洁,时间效率高。同时递归也是由缺点的:
栈帧深度太深,导致栈空间不够用,栈可能会溢出,当递归的次数到达一个很大的数值时,这时候开辟栈帧的空间就不够用了。
那么怎么将递归变成非递归,这里有两种方法。
1.直接将递归的思路改为循环来实现,不过只适用于简单的代码(比如就1+2+...+n的和)。
2.借助数据结构中的栈(队列)来模拟递归的过程。
第二种方法是今天将两个排序算法变成非递归的关键。
这是快速排序的基本思路,之前我们用了递归的思想来实现它,递归的本质是将Key值的左右区间存放起来,那么我们借助数据结构栈也可以存放。
每进行一步操作,都会用挖坑法(左右指针法和前后指针法均可,前文有详细讲解)中间取值,完成区间排序。当栈的元素全部被取完,排序完毕。
void QuickSortNonR(int* a, int n)
{
Stack st;
StackInit(&st);
StackPush(&st, n - 1);
StackPush(&st, 0);
while (!StackEmpty(&st))//当栈为空 则循环停止,排序完成
{
int left = StackTop(&st);
StackPop(&st);
int right = StackTop(&st);
StackPop(&st);
int KeyIndex = PartSort1(a, left, right);//挖坑法
//在这里必须从序列尾部压栈,因为栈是先进后出
if (KeyIndex + 1 < right)
{
StackPush(&st, right);
StackPush(&st, KeyIndex + 1);
}
if (KeyIndex - 1 > left)
{
StackPush(&st, KeyIndex - 1);
StackPush(&st, left);
}
}
StackDestory(&st);
}
实现归并排序的非递归我们利于循环来解决。
1.将8个数字以2为单位排序合并。
2.以4为单位将左右区间排序合并。
3.以8为单位将左右区间排序合并。
单位的变化可以用gap变量来实现,创造出一个循环。这是基本的思路,要实现非递归我们还需要进行条件优化。
当序列变为9个,10个那么两两位一组必定会发生越界访问。
要解决这个问题我们得将尾端合理化
//归并过程中的右半区间不存在
if (begin2 >= n)
break;
//归并过程中的右半区间算多了
if (end2 >= n)
{
end2 = n - 1;
}
void MergeSortNonR(int* a, int n)
{
int* tmp = (int*)malloc(sizeof(int) * n);
if (tmp == NULL)
{
printf("malloc fail!");
}
int gap = 1;
while (gap < n)
{
for (int i = 0; i < n; i += 2 * gap)
{
int begin1 = i, end1 = i + gap - 1;
int begin2 = i + gap, end2 = i + 2 * gap - 1;
//归并过程中的右半区间不存在
if (begin2 >= n)
break;
//归并过程中的右半区间算多了
if (end2 >= n)
{
end2 = n - 1;
}
int index = i;
while (begin1 <= end1 && begin2 <= end2)
{
if (a[begin1] > a[begin2])
{
tmp[index++] = a[begin2++];
}
else {
tmp[index++] = a[begin1++];
}
}
while (begin1 <= end1)
{
tmp[index++] = a[begin1++];
}
while (begin2 <= end2)
{
tmp[index++] = a[begin2++];
}
}
gap *= 2;
//拷贝回去
for (int j = 0; j < n; j++)
{
a[j] = tmp[j];
}
}
free(tmp);
}
好啦,这就是今天学习的分享啦!看到希望大家的三连呀!
如果有不当之处,欢迎大佬指正!