網站首頁 編程語言 正文
建議還不理解快速排序和歸并排序的小伙伴們可以先去看我上一篇博客??????哦!C語言超詳細講解排序算法下篇
1、棧溢出原因和遞歸的基本認識
我們先簡單來了解下內存分布結構:
棧區:用于存放地址、臨時變量等;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
堆區:程序運行期間動態分配所使用的場景;
靜態區:存放全局變量和靜態變量,具體還分為 .bss段和.data段;
? ? ? ? ? ? ???.bss段:存放未初始化的和初始化為0的全局變量或者靜態變量;
? ? ? ? ? ? ???.data段:初始化不為0的全局變量或者靜態變量;
常量區:存放常量(比如比變量名字,非0的初始化值,const常量,字符串等),只讀;
代碼區:存放代碼的位置,只讀;
?我們再來看這樣的一串代碼運行的結果:
這是一個累加求和的遞歸函數,當我們發現累加求和到1000遞歸仍然能正常執行,我們接著改為10000看看是否還能正常運行??
我們可以看到,當數值達到10000的時候程序已經崩了,并不會顯示任何錯誤,當我們進入調試可以發現報錯顯示棧溢出,那為什么會造成棧溢出呢,我們接著往下看!?
?遞歸的基本認識:
?遞歸本質也是函數調用,是函數調用,本質就要形成和釋放棧幀
?調用函數是有成本的,這個成本就體現在形成和釋放棧幀上:時間+空間
?所以,遞歸就是不斷形成棧幀的過程
內存和CPU的資源是有限的,也就決定了,合理的遞歸是絕對不能無限遞歸下去,如果遞歸調用深度太深,這樣有可能導致一 直開辟棧空間,最終產生棧空間耗盡的情況,這樣的現象我們稱為棧溢出!
既然使用遞歸極端情況下會出現棧溢出的問題,那么我們就用非遞歸的方式來實現快速排序和歸并排序!
2、快速排序(非遞歸實現)
快速排序非遞歸實現思想:
首先我們可以借助數據結構的棧來完成,遵循棧的后進先出,我們可以先入右再入左,然后使用我們上一期講的三個方法中的其中一個方法,這里我們選擇挖坑法,使用挖坑法我們可以看作成兩個區間也就是: [left, keyIndex - 1] 和 [keyIndex + 1, right],如果區間存在我們接著入棧,如此循環直到棧為空,則排序結束!
圖解見下:
?代碼實現如下:
//挖坑法 - 升序 int PartSort(int* a, int left, int right) { int begin = left; int end = right; int key = a[begin]; int pivot = begin; while (begin < end) { while (begin < end && a[end] >= key) { --end; } a[pivot] = a[end]; pivot = end; while (begin < end && a[begin] <= key) { ++begin; } a[pivot] = a[begin]; pivot = begin; } pivot = begin;//當begin與end相遇,隨便把begin和end的值給pivot a[pivot] = key; return pivot; } void QuickSortNonR(int* a, int n) { Stack st; StackInit(&st);//初始化棧 StackPush(&st, n - 1);//入數組最后一個元素下標 StackPush(&st, 0);//入數組第一個元素下標 while (!StackEmpty(&st))//當棧不為空我們就進入循環 { int left = StackTop(&st);//取出棧頂元素給left StackPop(&st);//出棧 - 刪除棧頂元素 int right = StackTop(&st); StackPop(&st); int keyIndex = PartSort(a, left, right);//使用挖坑法區間排序 //[left, keyIndex - 1] keyIndex [keyIndex + 1, right] - 分成子區間 if (keyIndex + 1 < right)//因棧后進先出的特性,所以先入右區間 { StackPush(&st, right); StackPush(&st, keyIndex + 1); } if (left < keyIndex - 1) { StackPush(&st, keyIndex - 1); StackPush(&st, left); } } StackDestory(&st);//銷毀棧 }
3、歸并排序(非遞歸實現)
歸并排序非遞歸實現思想:
上期我們知道歸并需要開辟一個數組,并且使用分治的算法來實現歸并排序,而非遞歸版本我們的思路也是差不多,先讓他們一個一個歸并,然后兩個兩個歸并,再接著四個四個一起歸并,具體圖解見下:
?代碼實現如下:
void MergeSortNonR(int* a, int n) { int* tmp = (int*)malloc(sizeof(int) * n); if (tmp == NULL) { perror("malloc:"); return; } int gap = 1;//gap為每組數據的個數,每次翻倍 while (gap < n) { for (int i = 0; i < n; i += 2 * gap) { //可以看成 [i, i + gap - 1] [i + gap, i + 2 * gap - 1] 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[begin1++]; } else { tmp[index++] = a[begin2++]; } } while (begin1 <= end1) { tmp[index++] = a[begin1++]; } while (begin2 <= end2) { tmp[index++] = a[begin2++]; } //拷貝進去 for (int j = i; j <= end2; ++j) { a[j] = tmp[j]; } } gap *= 2; } free(tmp); }
本期到這里就結束了,相信你們已經對非遞歸快速排序和歸并排序已經很了解了,非遞歸這兩個在校招中經常會考,加油把!
gitee(碼云):Mercury. (zzwlwp) - Gitee.com? ? ? ?
原文鏈接:https://blog.csdn.net/m0_61784621/article/details/123927140
相關推薦
- 2022-07-08 Python如何讀取csv文件時添加表頭/列名_python
- 2022-05-09 Python的Pandas時序數據詳解_python
- 2022-11-17 Kotlin?StateFlow單數據更新熱流設計與使用介紹_Android
- 2023-05-13 python中flatten()函數用法詳解_python
- 2021-12-18 死鎖的處理基本策略和常用方法
- 2022-07-18 SQL?Server中實現錯誤處理_MsSql
- 2023-04-12 C#?DataGridView行列轉換的具體實現_python
- 2023-07-07 springboot優雅處理異常
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支