C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之堆排序的優(yōu)化算法
在瀏覽本篇博文的小伙伴可先淺看一下上篇堆和堆排序的思想:
1.堆排序優(yōu)化算法
要堆堆排序算法進(jìn)行優(yōu)化我們首先要明白之前我們所寫(xiě)的堆排序有什么可以優(yōu)化的地方或者說(shuō)哪里寫(xiě)的不夠好?
void HeapSort(int* a, int size) { //小堆 HP hp; HeapInit(&hp); //O(N*logN) for (int i = 0; i < size; ++i) { HeapPush(&hp, a[i]); } size_t j = 0; //O(N*logN) while (!HeapEmpty(&hp)) { a[j] = HeapTop(&hp); j++; HeapPop(&hp); } HeapDestory(&hp); }
這是我們之前寫(xiě)的堆排序,我們能夠發(fā)現(xiàn),如果我們要實(shí)現(xiàn)堆排序的前提是我們要寫(xiě)一堆。那這想想都很麻煩,我們都知道排序算法那么多,我們何必選擇這種算法呢?
其次我們?cè)賮?lái)分析一下建堆的時(shí)間復(fù)雜度:
1.1建堆的時(shí)間復(fù)雜度
因?yàn)槎咽峭耆鏄?shù),而滿二叉樹(shù)也是完全二叉樹(shù),此處為了簡(jiǎn)化使用滿二叉樹(shù)來(lái)證明 ( 時(shí)間復(fù)雜度本來(lái)看的就是近似值,多幾個(gè)節(jié)點(diǎn)不影響最終結(jié)果) :
因?yàn)槲覀円M(jìn)行優(yōu)化建堆,在這里分析一下向下調(diào)整建堆和向上調(diào)整建堆的時(shí)間復(fù)雜度。
1.1.1 向下調(diào)整建堆:O(N)
過(guò)程分析如下:
因此向下調(diào)整建堆的時(shí)間復(fù)雜度為O(n)。
1.1.2 向上調(diào)整建堆:O(N*logN)
過(guò)程分析如下:
因此向上調(diào)整建堆的時(shí)間復(fù)雜度為O(N*logN)。
1.2堆排序的復(fù)雜度
1.2.1原堆排序的時(shí)間復(fù)雜度
我們來(lái)看原堆排序的代碼中使用了向上調(diào)整建堆,因此原排序的時(shí)間復(fù)雜度為O(N*logN)
1.2.2原堆排序的空間復(fù)雜度
因?yàn)槲覀円⒁粋€(gè)堆,我們實(shí)現(xiàn)堆是使用數(shù)組實(shí)現(xiàn),因此假設(shè)有要排序元素個(gè)數(shù)為N,空間復(fù)雜度為O(N)。
1.3堆排序優(yōu)化算法的復(fù)雜度
堆排序的優(yōu)化算法主要是對(duì)空間復(fù)雜度進(jìn)行優(yōu)化。由于我們之前建堆都要開(kāi)辟新的數(shù)組,因此我們是否可以在原數(shù)組上直接建堆,無(wú)需再開(kāi)辟新的空間建堆呢?答案當(dāng)然是可以的。以下使用的正是在原數(shù)組上直接建堆。
1.3.1 堆排序優(yōu)化算法的時(shí)間復(fù)雜度
由于使用堆排序,我們要利用堆的特點(diǎn),每次取堆頂?shù)脑?。因此每次取完?shù)據(jù)后都要對(duì)堆進(jìn)行調(diào)整。再次我們有向上調(diào)整和向下調(diào)整兩種算法,我們需要對(duì)這兩種算法分別分析選出一個(gè) 更優(yōu)的調(diào)整算法。
1.3.1.1向上調(diào)整--建堆 O(N*logN)
由于我們是對(duì)原數(shù)組之間建堆,因此我們?nèi)绻怯孟蛏险{(diào)整,在剛剛我們所分析的建堆的時(shí)間復(fù)雜度是O(N*logN)。
實(shí)現(xiàn)代碼:
向上調(diào)整--建堆 O(N*logN) int n = 1; while (n<size) { AdjustUp(a, n++); }
1.3.1.2向下調(diào)整-建堆 O(N)
由于向下調(diào)整的前提條件是左子樹(shù)和右子樹(shù)都已經(jīng)是一個(gè)堆,但是一個(gè)數(shù)組并不能保證是一個(gè)堆,那么我們不能直接對(duì)數(shù)組使用向下調(diào)整。因此我們需要將節(jié)點(diǎn)的左子樹(shù)右子樹(shù)變成堆再進(jìn)行向下調(diào)整。因此我們可以我們可以倒著來(lái)。
過(guò)程:
1、葉子節(jié)點(diǎn)不要調(diào),因?yàn)橐粋€(gè)節(jié)點(diǎn)可以看成堆。因此我們從倒數(shù)的第一個(gè)非葉子節(jié)點(diǎn)開(kāi)始調(diào)整。如果找到倒數(shù)第一個(gè)非葉子節(jié)點(diǎn)。那就是用最后一個(gè)節(jié)點(diǎn)找他的父節(jié)點(diǎn)就是最后一個(gè)非葉子節(jié)點(diǎn)。
parent = (child-1)/2。我們用size計(jì)算:child = size -1。因此parent = (size-1-1)/2。我們一直向上找就可以將數(shù)組變成一個(gè)堆。因此向下調(diào)整建堆的復(fù)雜度為O(N)。分析如上:
//向下調(diào)整--建堆 O(N) for (int i = (size - 1 - 1) / 2; i >= 0; --i) { AdjustDown(a, size, i); }
1.3.2 堆排序優(yōu)化算法的空間復(fù)雜度
由于我們是在原數(shù)組上進(jìn)行遍歷因此沒(méi)有開(kāi)辟新的空間。因此空間復(fù)雜度為O(1)。
1.4堆排序?qū)崿F(xiàn)邏輯
如果升序建小堆,最小的數(shù)已經(jīng)在堆頂,剩下的數(shù)關(guān)系打亂,需要重新建堆,建堆最好也要O(N),再選出次小的,不斷建堆選數(shù),如果這樣,還不如直接遍歷選數(shù)!!因此升序要建大堆?。?/strong>利用刪除的思想來(lái)玩。
過(guò)程:
1、把第一個(gè)數(shù)和最后一個(gè)數(shù)交換,由于是大堆,堆頂?shù)臄?shù)據(jù)一定是最大的數(shù)據(jù)。和最后一個(gè)數(shù)交換后,最大的數(shù)據(jù)就到了最后一個(gè)。
2、再對(duì)前N-1個(gè)數(shù)進(jìn)行向下調(diào)整建立新的大堆,次大的數(shù)放在了堆頂,我們?cè)僮尪秧數(shù)脑睾妥詈笠粋€(gè)元素交換(這個(gè)最后一個(gè)不是數(shù)組的最后一個(gè),是堆中的最后一個(gè),使用end進(jìn)行控制)。
3、當(dāng)end到0的時(shí)候,說(shuō)明已經(jīng)排完了。
//升序要建大堆, size_t end = size - 1; while (end > 0) { Swap(&a[0], &a[end]); AdjustDown(a, end, 0); end--; }
1.5堆排序?qū)崿F(xiàn)代碼
void HeapSort(int* a, int size) { //向下調(diào)整--建堆 O(N) for (int i = (size - 1 - 1) / 2; i >= 0; --i) { AdjustDown(a, size, i); } //如果升序建小堆,最小的數(shù)已經(jīng)在堆頂,剩下的數(shù)關(guān)系打亂,需要重新建堆,建堆最好也要O(N) //再選出次小的,不斷建堆選數(shù),如果這樣,還不如直接遍歷選數(shù)!! //升序要建大堆, size_t end = size - 1; while (end > 0) { Swap(&a[0], &a[end]); AdjustDown(a, end, 0); end--; } } int main() { int a[] = { 4,2,1,3,5,7,9,8,6}; HeapSort(a,sizeof(a)/sizeof(int)); for (int i = 0; i < sizeof(a) / sizeof(int); ++i) { printf("%d ", a[i]); } return 0; }
1.6演示結(jié)果
總結(jié)
到此這篇關(guān)于C語(yǔ)言數(shù)據(jù)結(jié)構(gòu)之堆排序優(yōu)化算法的文章就介紹到這了,更多相關(guān)C語(yǔ)言堆排序優(yōu)化算法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- C語(yǔ)言排序之?堆排序
- C語(yǔ)言詳解如何實(shí)現(xiàn)堆及堆的結(jié)構(gòu)與接口
- C語(yǔ)言植物大戰(zhàn)數(shù)據(jù)結(jié)構(gòu)堆排序圖文示例
- C語(yǔ)言植物大戰(zhàn)數(shù)據(jù)結(jié)構(gòu)二叉樹(shù)堆
- C語(yǔ)言堆與二叉樹(shù)的順序結(jié)構(gòu)與實(shí)現(xiàn)
- C語(yǔ)言函數(shù)調(diào)用堆棧詳情分析
- C語(yǔ)言實(shí)現(xiàn)堆的簡(jiǎn)單操作的示例代碼
- C語(yǔ)言中的二叉樹(shù)和堆詳解
- C語(yǔ)言堆實(shí)現(xiàn)建堆算法和堆排序
相關(guān)文章
Objective-C中使用STL標(biāo)準(zhǔn)庫(kù)Queue隊(duì)列的方法詳解
這篇文章主要介紹了Objective-C中使用STL標(biāo)準(zhǔn)庫(kù)Queue隊(duì)列的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01程序員都不知道C語(yǔ)言中的這些小細(xì)節(jié)
本文通過(guò)7到實(shí)例題目給大家展示C語(yǔ)言中的一些小細(xì)節(jié),很少有朋友真正的掌握,感興趣的朋友跟隨小編一起看看吧2021-05-05C++實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了C++實(shí)現(xiàn)簡(jiǎn)單計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05深入C++浮點(diǎn)數(shù)無(wú)效值定義與判定的解決辦法
本篇文章是對(duì)C++中浮點(diǎn)數(shù)無(wú)效值定義與判定進(jìn)行了介紹,需要的朋友參考下2013-05-05c++利用vector創(chuàng)建二維數(shù)組的幾種方法總結(jié)
這篇文章主要介紹了c++利用vector創(chuàng)建二維數(shù)組的幾種方法總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11C語(yǔ)言?超詳細(xì)講解算法的時(shí)間復(fù)雜度和空間復(fù)雜度
算法復(fù)雜度分為時(shí)間復(fù)雜度和空間復(fù)雜度。其作用:?時(shí)間復(fù)雜度是度量算法執(zhí)行的時(shí)間長(zhǎng)短;而空間復(fù)雜度是度量算法所需存儲(chǔ)空間的大小2022-03-03