【数据结构与算法】快速排序的非递归实现方法

简介: 【数据结构与算法】快速排序的非递归实现方法

一.前言

如果数据量过大的话,不断递归就会出现栈溢出的现象,这个时候你的代码是没问题的,但就是跑不起来,这个时候就要把递归改成非递归

一般有两种改法:

1.直接改,利用循环等;

2.借助栈的辅助。

快速排序的非递归实现方法就需要借助栈的辅助

二.非递归实现

通过观察我们发现,每次递归调用传过去的是一个数组和一个区间,数组自不用说,这个区间就是我们的突破点

也就是说我们只要想办法在循环的时候拿到本次要排序的区间就行了,那要怎么做呢?

借助数据结构:栈,栈具有后进先出的特性,借助这个就能很好的解决问题。

1.首先要先把 left 和 right 入栈,这样栈此时就不为空,然后开始循环。

2.取出栈顶的两个数据,分别赋给 begin 和 end ,注意在这之后要pop掉取出的数据

3.然后就是快排的逻辑,有三种方法,哪种都可以;

  如果不清楚这三种方法的话,请点击:快速排序的三种实现方法

  走完一趟后就得到了 keyi

4.然后数组就被 keyi 分成了两个子区间,分别是:

    左区间:[begin,keyi-1]

    右区间:[keyi+1,end]

分别将左区间和右区间入栈,注意这里要判断:

      a.keyi+1<end

      b.keyi-1>begin

否则会出现数组访问越界或是死循环的情况。

5.因为栈是后进先出,所以要是想先排左区间的话,就要先入右区间进栈,反之;

6.循环结束后,销毁栈

1. void QuickSortNonR(Sdatatype* arr, int left, int right)
2. {
3.  ST st;
4.  Stackinit(&st);
5. 
6.  Stackpush(&st, right);
7.  Stackpush(&st, left);
8.  while (!Stackempty(&st))   //栈为空时就结束循环
9.  {
10.     int begin = Stacktop(&st);   //出一个就要pop掉一个数据
11.     Stackpop(&st);
12.     int end = Stacktop(&st);
13.     Stackpop(&st);
14.     int keyi = begin;    //以下为快速排序的逻辑,这里用的是前后指针法实现
15.     int mid = GetMid(arr, begin, end);
16.     if (mid != keyi)
17.       Swap(&arr[mid], &arr[keyi]);
18.     int prev = begin, cur = begin + 1;
19.     while (cur <= end)
20.     {
21.       if (arr[cur] < arr[keyi])
22.       {
23.         prev++;
24.         Swap(&arr[cur], &arr[prev]);
25.         cur++;
26.       }
27.       else
28.         cur++;
29.     }
30.     Swap(&arr[keyi], &arr[prev]);
31.     keyi = prev;   
32.     if (keyi + 1 < end)    //不要忘记判断
33.     {
34.       Stackpush(&st, end);    //这里是先入的右区间,所以是先排序左区间
35.       Stackpush(&st, keyi + 1);
36.     }
37.     if (keyi - 1 > begin)
38.     {
39.       Stackpush(&st, keyi - 1);
40.       Stackpush(&st, begin);
41.     }
42.   }
43. 
44.   Stackdestroy(&st);   //销毁栈
45. }

🐬🤖本篇文章到此就结束了,若有错误或是建议的话,欢迎小伙伴们指出;🕊️👻

😄😆希望小伙伴们能支持支持博主啊,你们的支持对我很重要哦;🥰🤩

😍😁谢谢你的阅读。😸😼


目录
相关文章
|
18天前
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
23 1
|
2月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
47 3
|
21天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
38 2
|
2月前
|
Java C++ 索引
让星星⭐月亮告诉你,LinkedList和ArrayList底层数据结构及方法源码说明
`LinkedList` 和 `ArrayList` 是 Java 中两种常见的列表实现。`LinkedList` 基于双向链表,适合频繁的插入和删除操作,但按索引访问元素效率较低。`ArrayList` 基于动态数组,支持快速随机访问,但在中间位置插入或删除元素时性能较差。两者均实现了 `List` 接口,`LinkedList` 还额外实现了 `Deque` 接口,提供了更多队列操作。
26 3
|
2月前
|
算法 索引
HashMap扩容时的rehash方法中(e.hash & oldCap) == 0算法推导
HashMap在扩容时,会创建一个新数组,并将旧数组中的数据迁移过去。通过(e.hash & oldCap)是否等于0,数据被巧妙地分为两类:一类保持原有索引位置,另一类索引位置增加旧数组长度。此过程确保了数据均匀分布,提高了查询效率。
42 2
|
2月前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
24 1
|
2月前
|
存储 算法 Java
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
前缀(波兰)表达式、中缀表达式和后缀(逆波兰)表达式的基本概念、计算机求值方法,以及如何将中缀表达式转换为后缀表达式,并提供了相应的Java代码实现和测试结果。
76 0
数据结构与算法学习八:前缀(波兰)表达式、中缀表达式、后缀(逆波兰)表达式的学习,中缀转后缀的两个方法,逆波兰计算器的实现
|
2月前
|
存储
ES6中的Set数据结构的常用方法和使用场景
ES6中的Set数据结构的常用方法和使用场景
|
2月前
|
存储 算法 索引
HashMap底层数据结构及其增put删remove查get方法的代码实现原理
HashMap 是基于数组 + 链表 + 红黑树实现的高效键值对存储结构。默认初始容量为16,负载因子为0.75。当存储元素超过容量 * 负载因子时,会进行扩容。HashMap 使用哈希算法计算键的索引位置,通过链表或红黑树解决哈希冲突,确保高效存取。插入、获取和删除操作的时间复杂度接近 O(1)。
29 0
|
2月前
|
算法 定位技术
数据结构与算法学习九:学习递归。递归的经典实例:打印问题、阶乘问题、递归-迷宫问题、八皇后问题
本文详细介绍了递归的概念、重要规则、形式,并展示了递归在解决打印问题、阶乘问题、迷宫问题和八皇后问题等经典实例中的应用。
45 0