欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語言非遞歸算法解決快速排序與歸并排序產(chǎn)生的棧溢出

 更新時間:2022年04月06日 09:33:48   作者:程序猿教你打籃球  
上期我們講完了排序算法下,不知道小伙伴們有沒有發(fā)現(xiàn)一個問題,快速排序和歸并排序我們都是用遞歸來實現(xiàn)的,可能有小伙伴會問,如果說數(shù)據(jù)量很多話,棧區(qū)空間會不會不夠用呢?這期我們就來解決使用遞歸實現(xiàn)的排序?qū)е聴R绯鋈绾谓鉀Q

建議還不理解快速排序和歸并排序的小伙伴們可以先去看我上一篇博客??????哦!C語言超詳細(xì)講解排序算法下篇

1、棧溢出原因和遞歸的基本認(rèn)識

我們先簡單來了解下內(nèi)存分布結(jié)構(gòu):

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56iL5bqP54y_5pWZ5L2g5omT56-u55CD,size_20,color_FFFFFF,t_70,g_se,x_16

棧區(qū):用于存放地址、臨時變量等;? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

堆區(qū):程序運行期間動態(tài)分配所使用的場景;

靜態(tài)區(qū):存放全局變量和靜態(tài)變量,具體還分為 .bss段和.data段;

? ? ? ? ? ? ???.bss段:存放未初始化的和初始化為0的全局變量或者靜態(tài)變量;

? ? ? ? ? ? ???.data段:初始化不為0的全局變量或者靜態(tài)變量;

常量區(qū):存放常量(比如比變量名字,非0的初始化值,const常量,字符串等),只讀;

代碼區(qū):存放代碼的位置,只讀;

?我們再來看這樣的一串代碼運行的結(jié)果:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56iL5bqP54y_5pWZ5L2g5omT56-u55CD,size_20,color_FFFFFF,t_70,g_se,x_16

這是一個累加求和的遞歸函數(shù),當(dāng)我們發(fā)現(xiàn)累加求和到1000遞歸仍然能正常執(zhí)行,我們接著改為10000看看是否還能正常運行??

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56iL5bqP54y_5pWZ5L2g5omT56-u55CD,size_20,color_FFFFFF,t_70,g_se,x_16

我們可以看到,當(dāng)數(shù)值達(dá)到10000的時候程序已經(jīng)崩了,并不會顯示任何錯誤,當(dāng)我們進(jìn)入調(diào)試可以發(fā)現(xiàn)報錯顯示棧溢出,那為什么會造成棧溢出呢,我們接著往下看!?

?遞歸的基本認(rèn)識:

?遞歸本質(zhì)也是函數(shù)調(diào)用,是函數(shù)調(diào)用,本質(zhì)就要形成和釋放棧幀

?調(diào)用函數(shù)是有成本的,這個成本就體現(xiàn)在形成和釋放棧幀上:時間+空間

?所以,遞歸就是不斷形成棧幀的過程

內(nèi)存和CPU的資源是有限的,也就決定了,合理的遞歸是絕對不能無限遞歸下去,如果遞歸調(diào)用深度太深,這樣有可能導(dǎo)致一 直開辟??臻g,最終產(chǎn)生??臻g耗盡的情況,這樣的現(xiàn)象我們稱為棧溢出!

既然使用遞歸極端情況下會出現(xiàn)棧溢出的問題,那么我們就用非遞歸的方式來實現(xiàn)快速排序和歸并排序!

2、快速排序(非遞歸實現(xiàn))

快速排序非遞歸實現(xiàn)思想:

首先我們可以借助數(shù)據(jù)結(jié)構(gòu)的棧來完成,遵循棧的后進(jìn)先出,我們可以先入右再入左,然后使用我們上一期講的三個方法中的其中一個方法,這里我們選擇挖坑法,使用挖坑法我們可以看作成兩個區(qū)間也就是: [left, keyIndex - 1] 和 [keyIndex + 1, right],如果區(qū)間存在我們接著入棧,如此循環(huán)直到棧為空,則排序結(jié)束!

圖解見下:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56iL5bqP54y_5pWZ5L2g5omT56-u55CD,size_20,color_FFFFFF,t_70,g_se,x_16

?代碼實現(xiàn)如下:

//挖坑法 - 升序
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;//當(dāng)begin與end相遇,隨便把begin和end的值給pivot
	a[pivot] = key;
 
	return pivot;
}
 
void QuickSortNonR(int* a, int n)
{
	Stack st;
	StackInit(&st);//初始化棧
	StackPush(&st, n - 1);//入數(shù)組最后一個元素下標(biāo)
	StackPush(&st, 0);//入數(shù)組第一個元素下標(biāo)
 
	while (!StackEmpty(&st))//當(dāng)棧不為空我們就進(jìn)入循環(huán)
	{
		int left = StackTop(&st);//取出棧頂元素給left
		StackPop(&st);//出棧 - 刪除棧頂元素
 
		int right = StackTop(&st);
		StackPop(&st);
 
		int keyIndex =  PartSort(a, left, right);//使用挖坑法區(qū)間排序
 
		//[left, keyIndex - 1] keyIndex [keyIndex + 1, right]  -  分成子區(qū)間
 
		if (keyIndex + 1 < right)//因棧后進(jìn)先出的特性,所以先入右區(qū)間
		{
			StackPush(&st, right);
			StackPush(&st, keyIndex + 1);
		}
 
		if (left < keyIndex - 1)
		{
			StackPush(&st, keyIndex - 1);
			StackPush(&st, left);
		}
	}
 
	StackDestory(&st);//銷毀棧
}

3、歸并排序(非遞歸實現(xiàn))

歸并排序非遞歸實現(xiàn)思想:

上期我們知道歸并需要開辟一個數(shù)組,并且使用分治的算法來實現(xiàn)歸并排序,而非遞歸版本我們的思路也是差不多,先讓他們一個一個歸并,然后兩個兩個歸并,再接著四個四個一起歸并,具體圖解見下:

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA56iL5bqP54y_5pWZ5L2g5omT56-u55CD,size_20,color_FFFFFF,t_70,g_se,x_16

?代碼實現(xiàn)如下:

void MergeSortNonR(int* a, int n)
{
	int* tmp = (int*)malloc(sizeof(int) * n);
	if (tmp == NULL)
	{
		perror("malloc:");
		return;
	}
 
	int gap = 1;//gap為每組數(shù)據(jù)的個數(shù),每次翻倍
 
	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;
 
			//歸并過程中右半?yún)^(qū)間有可能不存在!
			if (begin2 >= n)
				break;
			//歸并過程中右半?yún)^(qū)間越界了,就修正下
			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++];
			}
 
			//拷貝進(jìn)去
			for (int j = i; j <= end2; ++j)
			{
				a[j] = tmp[j];
			}
 		}
		gap *= 2;
	}
	free(tmp);
}

本期到這里就結(jié)束了,相信你們已經(jīng)對非遞歸快速排序和歸并排序已經(jīng)很了解了,非遞歸這兩個在校招中經(jīng)常會考,加油把!

gitee(碼云):Mercury. (zzwlwp) - Gitee.com? ? ? ?

到此這篇關(guān)于C語言非遞歸算法解決快速排序與歸并排序產(chǎn)生的棧溢出的文章就介紹到這了,更多相關(guān)C語言 棧溢出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++簡明講解類型轉(zhuǎn)換的使用與作用

    C++簡明講解類型轉(zhuǎn)換的使用與作用

    類型轉(zhuǎn)換(type?cast),是高級語言的一個基本語法。它被實現(xiàn)為一個特殊的運算符,以小括號內(nèi)加上類型名來表示,接下來讓我們一起來詳細(xì)了解
    2022-04-04
  • c語言實現(xiàn)24小時制轉(zhuǎn)換為12小時制示例

    c語言實現(xiàn)24小時制轉(zhuǎn)換為12小時制示例

    這篇文章主要介紹了c語言實現(xiàn)24小時制轉(zhuǎn)換為12小時制示例,需要的朋友可以參考下
    2014-04-04
  • C語言課程設(shè)計之抽獎系統(tǒng)

    C語言課程設(shè)計之抽獎系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言課程設(shè)計之抽獎系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • c++網(wǎng)絡(luò)編程下Linux的epoll技術(shù)和Windows下的IOCP模型

    c++網(wǎng)絡(luò)編程下Linux的epoll技術(shù)和Windows下的IOCP模型

    c++ 網(wǎng)絡(luò)編程LINUX-epoll/windows-IOCP下socket opoll函數(shù)用法 優(yōu)于select方法的epoll 以及windows下IOCP 解決多進(jìn)程服務(wù)端創(chuàng)建進(jìn)程資源浪費問題,感興趣的小伙伴一起來學(xué)習(xí)吧
    2021-08-08
  • C++發(fā)送HTTP請求的實現(xiàn)代碼

    C++發(fā)送HTTP請求的實現(xiàn)代碼

    這篇文章主要介紹了C++發(fā)送HTTP請求的實現(xiàn)代碼,需要的朋友可以參考下
    2014-06-06
  • C++讀寫ini配置文件實現(xiàn)過程詳解

    C++讀寫ini配置文件實現(xiàn)過程詳解

    這篇文章主要介紹了C++讀寫ini配置文件實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-07-07
  • Linux C 時間函數(shù)應(yīng)用

    Linux C 時間函數(shù)應(yīng)用

    本文是關(guān)于Linux C時間函數(shù) time_t struct tm 進(jìn)行了詳細(xì)的分析介紹并有應(yīng)用實例,希望能幫到有需要的同學(xué)
    2016-07-07
  • C++ OpenCV讀寫XML或YAML文件的方法詳解

    C++ OpenCV讀寫XML或YAML文件的方法詳解

    XML是一種元標(biāo)記語言。所謂元標(biāo)記,就是開發(fā)者可以根據(jù)自身需要定義自己的標(biāo)記。YAML是一個可讀性高,用來表達(dá)資料序列的格式。本文將通過C++和OpenCV實現(xiàn)這兩種文件的讀寫,需要的可以參考一下
    2022-05-05
  • C++實現(xiàn)LeetCode(64.最小路徑和)

    C++實現(xiàn)LeetCode(64.最小路徑和)

    這篇文章主要介紹了C++實現(xiàn)LeetCode(64.最小路徑和),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C語言代碼實現(xiàn)簡單掃雷小游戲

    C語言代碼實現(xiàn)簡單掃雷小游戲

    這篇文章主要為大家詳細(xì)介紹了C語言實現(xiàn)掃雷游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-01-01

最新評論