【數據結構與算法】堆排序算法原理與實現:基于堆實現的高效排序算法

? ?

??????????? 💓 博客主頁:倔強的石頭的CSDN主頁?

???????????📝Gitee主頁:倔強的石頭的gitee主頁

? ? ? ? ? ? ? 文章專欄:《數據結構與算法》

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ????期待您的關注

?

1b7335aca73b41609b7f05d1d366f476.gif?

?

目錄

一、引言

堆排序的簡介

堆排序的特點

二、堆的概念

三、堆排序算法的原理

四、堆排序的步驟

🍃構建堆?

🍃交換與調整

🍃重復過程

五、堆排序的性能分析

🍃時間復雜度:

🍃空間復雜度:

六、示例代碼

七、總結


?

一、引言

堆排序的簡介

堆排序(Heap Sort)是一種基于堆數據結構實現的排序算法。利用堆這種數據結構的高效性,通過構建和調整堆來實現排序,是一種性能優秀的排序算法。

堆排序的特點

  1. 時間復雜度:堆排序的最壞、最好、平均時間復雜度均為O(nlogn),其中n是待排序元素的數量。
  2. 穩定性:堆排序在排序過程中相等的元素不會交換位置,因此它是穩定的排序算法。
  3. 選擇排序:堆排序是一種選擇排序,它總是選擇當前未排序部分的最大(或最小)元素進行排序。

?

二、堆的概念

關于堆的詳細介紹,參考前置文章

【數據結構與算法】探索數組在堆數據結構中的妙用:從原理到實現-CSDN博客

?

三、堆排序算法的原理

  • 堆排序的基本思想是將待排序的序列構建成一個堆,然后依次將堆頂元素與堆尾元素交換,并將堆的大小減小1,再對剩余的堆進行調整,使其滿足堆的性質。
  • 重復這個過程,直到堆的大小為1,此時排序完成。?

四、堆排序的步驟

🍃構建堆?

借助建堆算法,降序建小堆,升序建大堆,可以選擇向上或者向下調整算法

向上調整建堆的原理:
模仿堆的插入操作來構建堆,從第一個子結點開始,將它看做是新插入的元素,向上調整至滿足堆的性質,然后依次往后走,直到最后一個葉子節點完成上述調整

向下調整建堆的原理:
從最后一個父結點開始,先保證它和左右子樹成為堆,然后依次往前走,保證每個父結點與左右子樹成堆,直到最后根結點與左右子樹成堆

?

關于建堆的向上調整算法和向下調整算法有時間復雜度推導

限于篇幅,這里就不展開推導了,直接給出結論

  • 向下調整建堆的時間復雜度為O(N)
  • 向上調整算法的時間復雜度為O(n*logN)

向下調整算法優于向上調整,所以應該選擇向下調整算法

?這里分別給出向下調整建小堆和向下調整建大堆的算法

(如果關于向上調整算法和向下調整算法有疑惑,建議了解完堆的這篇文章之后再來看

【數據結構與算法】探索數組在堆數據結構中的妙用:從原理到實現-CSDN博客)

void Adjustdownsmall(DataType* a, int parent, int size)//向下調整建小堆算法
{int child = parent * 2 + 1;//先假定左孩子小while (child < size)//循環條件是未調整至葉子節點{if (child + 1 < size && a[child + 1] < a[child])//如果右孩子存在且更小,改變為右孩子child++;if (a[child] < a[parent])//如果子節點小于父節點,交換位置{Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}elsebreak;}
}
void Adjustdownbig(DataType* a, int parent, int size)//向下調整建大堆算法
{int child = parent * 2 + 1;//先假定左孩子大while (child < size)//循環條件是未調整至葉子節點{if (child + 1 < size && a[child + 1] > a[child])//如果右孩子存在且更大,改變為右孩子child++;if (a[child] > a[parent])//如果子節點大于父節點,交換位置{Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}elsebreak;}
}


?

🍃交換與調整

建堆之后,就是排序
以降序為例,每次將堆頂與堆尾數據交換(相當于將當前的最小值挪到最后),然后堆尾數據偽刪除(有效數據個數--,不是真刪除)進行一輪向下調整,恢復堆的結構

?

Swap(&a[0], &a[end]);//交換堆頂和堆尾數據
end--;
Adjustdownsmall(a, 0, end);//向下調整恢復堆的結構

?9b7e5cb844404312a312e019bae3b8bd.png

?

🍃重復過程

?重復上述交換與調整的過程,直到堆的大小為1,此時排序完成。

?

五、堆排序的性能分析

🍃時間復雜度:

  1. 建堆:對于長度為n的數組,建堆的時間復雜度為O(n)。這是因為建堆的過程中,元素需要逐個從數組尾部加入到堆中,并重新調整堆的結構以維持其性質。每個元素加入堆中最多會觸發從該元素到根節點的路徑上元素的重新調整,因此,平均而言,每個元素會觸發O(log n)次調整。所以,建堆的總時間復雜度為O(n *log n)。但是,由于建堆的過程是線性的(從最后一個非葉子節點開始,逐個向上調整),所以實際的時間復雜度為O(n)。
  2. 排序:在排序階段,每次從堆頂取出最大(或最小)元素,并重新調整堆結構的時間復雜度為O(log n)。因為需要排序n個元素,所以排序階段的時間復雜度為O(n *log n)。

綜上,堆排序的總時間復雜度為O(n) + O(n *log n) = O(n *log n)。

?

🍃空間復雜度:

堆排序的空間復雜度為O(1)。這是因為堆排序是原地排序算法,它只需要常數個額外的空間來存儲臨時變量,而不需要額外的存儲空間來存儲待排序的數組。所有的操作都是直接在原數組上進行的。所以,堆排序的空間復雜度非常低。

六、示例代碼

(分別給出了完整的降序排序算法和升序排序算法)

#include<stdio.h>
#include<stdlib.h>#if 1
//堆排序
typedef int DataType;
void Swap(DataType* a, DataType* b)
{DataType tmp = *a;*a = *b;*b = tmp;
}
void Adjustdownsmall(DataType* a, int parent, int size)//向下調整建小堆算法
{int child = parent * 2 + 1;//先假定左孩子小while (child < size)//循環條件是未調整至葉子節點{if (child + 1 < size && a[child + 1] < a[child])//如果右孩子存在且更小,改變為右孩子child++;if (a[child] < a[parent])//如果子節點小于父節點,交換位置{Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}elsebreak;}
}
void Adjustdownbig(DataType* a, int parent, int size)//向下調整建大堆算法
{int child = parent * 2 + 1;//先假定左孩子大while (child < size)//循環條件是未調整至葉子節點{if (child + 1 < size && a[child + 1] > a[child])//如果右孩子存在且更大,改變為右孩子child++;if (a[child] > a[parent])//如果子節點大于父節點,交換位置{Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}elsebreak;}
}void HeapSortDOrder(DataType* a,int size)//降序排序
{//向下調整建小堆for (int i = (size - 2) / 2; i >= 0; i--)//從最后一個父節點調整{Adjustdownsmall(a, i, size);}int end = size - 1;while (end>0){Swap(&a[0], &a[end]);//交換堆頂和堆尾數據end--;Adjustdownsmall(a, 0, end);//向下調整恢復堆的結構}
}
void HeapSortAOrder(DataType* a, int size)//升序排序
{//向下調整建大堆for (int i = (size - 2) / 2; i >= 0; i--)//從最后一個父節點調整{Adjustdownbig(a, i, size);}int end = size - 1;while (end > 0){Swap(&a[0], &a[end]);//交換堆頂和堆尾數據end--;Adjustdownbig(a, 0, end);//向下調整恢復堆的結構}
}
#endifvoid print(DataType* a, int size)
{for (int i = 0; i < size; i++){printf("%d ", a[i]);}printf("\n");
}
int main()
{int arr[] = { 12,3,5,78,46,15,23,19,20,36,52 };int size = sizeof(arr) / sizeof(arr[0]);HeapSortDOrder(arr, size);//降序print(arr, size);HeapSortAOrder(arr, size);//升序print(arr, size);}

?27c88bb4be3d4b43beb24363a0fd02ae.png

七、總結

堆排序算法是一種高效且實用的排序算法,它通過利用堆數據結構的特點和性質,實現了對數據的高效排序。在實際應用中,我們可以根據問題的特點選擇使用堆排序算法,以提高程序的性能和效率。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/38057.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/38057.shtml
英文地址,請注明出處:http://en.pswp.cn/web/38057.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

15kg級彈簧刀高速巡飛無人機技術詳解

彈簧刀高速巡飛無人機&#xff0c;作為一種先進的戰術導彈系統&#xff0c;融合了無人機與導彈的雙重特性&#xff0c;成為了現代戰爭中不可或缺的偵察與打擊利器。該無人機以其小巧的外形設計、優異的性能表現和廣泛的適用領域&#xff0c;受到了全球軍事領域的廣泛關注。彈簧…

【吊打面試官系列-MyBatis面試題】Mybatis 是如何進行分頁的?分頁插件的原理是什么?

大家好&#xff0c;我是鋒哥。今天分享關于 【Mybatis 是如何進行分頁的&#xff1f;分頁插件的原理是什么&#xff1f;】面試題&#xff0c;希望對大家有幫助&#xff1b; Mybatis 是如何進行分頁的&#xff1f;分頁插件的原理是什么&#xff1f; Mybatis 使用 RowBounds 對象…

怎么測試遠程服務器能否連通

遠程服務器連接測試的方法很多&#xff0c;下面簡單介紹下其中兩種方法。 ping命令 按WINR快截鍵&#xff0c;打開“運行”對話框&#xff0c;輸入cmd&#xff0c;回車&#xff0c;打開命令提示符。 輸入ping IP地址或ping 域名即可&#xff0c;如ping360服務器通不通&#xf…

32 lambda表達式

c11 c98例子 在c98中&#xff0c;如果想要對一個數據集合中的元素進行排序&#xff0c;可以適用std::sort方法 #include <algorithm>#include <functional>int main(){int array[] {4,1,8,5,3,7,0,9,2,6};// 默認按照小于比較&#xff0c;排出來結果是升序 std…

Django + Vue 實現圖片上傳功能的全流程配置與詳細操作指南

文章目錄 前言圖片上傳步驟1. urls 配置2. settings 配置3. models 配置4. 安裝Pillow 前言 在現代Web應用中&#xff0c;圖片上傳是一個常見且重要的功能。Django作為強大的Python Web框架&#xff0c;結合Vue.js這樣的現代前端框架&#xff0c;能夠高效地實現這一功能。本文將…

【Arduino】小飛魚通達二開實驗ESP32使用紅外尋跡傳感器 (圖文)

在智能小車項目中都會有一個功能就是自動巡線&#xff0c;今天小飛魚通達來實驗的就是這個紅外尋跡傳感器。 紅外尋跡傳感器的原理就是有一個小燈發出紅外光&#xff0c;光線照到物體后進行反射&#xff0c;有一個接收器進行接收&#xff0c;當在一定距離內會導通電路&#xf…

網安加·百家講壇 | 肖文棣:鑄盾護企——面對勒索病毒產業鏈的企業防護之道

作者簡介&#xff1a;肖文棣&#xff0c;OWASP中國廣東分會負責人、網安加社區特聘專家&#xff0c;現任某外企安全架構師&#xff0c;負責應用安全設計、管理和評審等工作。 引言 隨著信息技術的飛速發展&#xff0c;網絡安全問題愈發凸顯&#xff0c;企業面臨的網絡安全威脅…

HarmonyOS NEXT Beta 版開發者及先鋒用戶招募(第一期)報名答題題庫(持續更新中,僅供學習分享使用)

判斷題 All True. 單選題 關于容器組件Row和Column&#xff0c;下面說法錯誤的是&#xff1a; A A. justifyContent用于設置子組件在交叉軸方向上的對齊格式。 B. Row容器主軸為水平方向&#xff0c;Column容器主軸為垂直方向。 C. justifyContent用于設置子組件在主軸方向上的…

瞎談指令集和寄存器讀寫來驅動硬件

文章目錄 前言一、到底什么是指令集&#xff1f;二、為什么現代CPU需要指令集&#xff1f;三、開發完指令集究竟有什么缺點&#xff1f;四、寄存器讀寫怎么驗證&#xff1f;總結 前言 其實很早以前就想對這個話題展開來聊聊&#xff0c;但是對體系結構的理解也僅僅限于《量化體…

應急響應:應急響應流程,常見應急事件及處置思路

「作者簡介」&#xff1a;冬奧會網絡安全中國代表隊&#xff0c;CSDN Top100&#xff0c;就職奇安信多年&#xff0c;以實戰工作為基礎著作 《網絡安全自學教程》&#xff0c;適合基礎薄弱的同學系統化的學習網絡安全&#xff0c;用最短的時間掌握最核心的技術。 這一章節我們需…

交通氣象站:保障道路暢通的守護者

隨著現代社會的飛速發展&#xff0c;交通網絡日益密集&#xff0c;人們的出行越來越依賴于公路、鐵路和航空等交通方式。然而&#xff0c;多變的天氣條件常常給交通安全帶來隱患&#xff0c;如大霧、雨雪、強風等惡劣天氣不僅影響行車視線&#xff0c;還可能造成路面濕滑、結冰…

在我們實際使用中,線程池的大小配置多少合適?

線程池的大小配置是一個需要根據具體應用場景和資源情況來決定的問題。沒有一個固定的數字適用于所有情況&#xff0c;但是可以遵循一些通用的原則和方法來確定合適的線程池大小&#xff0c;我們來看一下通用原則和方法都有哪幾個維度。 通用原則和方法 1. CPU密集型任務&…

第十四屆藍橋杯省賽C++B組D題【飛機降落】題解(AC)

解題思路 這道題目要求我們判斷給定的飛機是否都能在它們的油料耗盡之前降落。為了尋找是否存在合法的降落序列&#xff0c;我們可以使用深度優先搜索&#xff08;DFS&#xff09;的方法&#xff0c;嘗試所有可能的降落順序。 首先&#xff0c;我們需要理解題目中的條件。每架…

【MotionCap】pycharm 遠程在wsl2 ubuntu20.04中root的miniconda3環境

pycharm wsl2 鏈接到pycharmsbin 都能看到內容,/root 下內容賦予了zhangbin 所有,pycharm還是看不到/root 下內容。sudo 安裝了miniconda3 引發了這些問題 由于是在 root 用戶安裝的miniconda3 所以安裝路徑在/root/miniconda3 里 這導致了環境也是root用戶的,會觸發告警 WA…

沖擊試樣缺口拉刀V2U2U3U5

拉刀性能介紹 沖擊試樣缺口拉刀采用進口高速工具鋼W18Cr4V材質&#xff0c;特殊工藝精密加工制造&#xff0c;硬度高&#xff0c;耐磨性好&#xff0c;使用壽命長&#xff0c;每把拉刀可加工試樣達20&#xff0c;000多個。拉刀共54個齒&#xff08;深度5mm缺口拉刀為74個齒&am…

抖音本地生活服務商條件太高怎么辦?低門檻方法來了!

隨著本地生活賽道的潛力不斷顯現&#xff0c;本地生活服務商的數量也在與日俱增。而在所有開通本地生活服務板塊的互聯網平臺中&#xff0c;日活躍用戶數約8億的抖音往往是眾多創業者優先考慮的對象&#xff0c;以抖音本地生活服務商如何申請為代表的相關問題也因此常出現在多個…

排序算法(1)之插入排序----直接插入排序和希爾排序

個人主頁&#xff1a;C忠實粉絲 歡迎 點贊&#x1f44d; 收藏? 留言? 加關注&#x1f493;本文由 C忠實粉絲 原創 排序之插入排序----直接插入排序和希爾排序(1) 收錄于專欄【數據結構初階】 本專欄旨在分享學習數據結構學習的一點學習筆記&#xff0c;歡迎大家在評論區交流討…

頁面加載503 Service Temporarily Unavailable異常

最近發現網頁刷新經常503&#xff0c;加載卡主&#xff0c;刷新頁面就正常了。 研究之后發現是頁面需要的js文件等加載失敗了。 再研究之后發現是nginx配置的問題。 我之前為了解決一個漏洞檢測到目標主機可能存在緩慢的HTTP拒絕服務攻擊 把nginx的連接設置了很多限制&#…

PHP傳奇游戲推廣信息發布站程序源碼帶會員發布

這是一個游戲導航網站程序。可以做任何一款游戲的推廣發布&#xff0c;會員注冊發布&#xff0c;后臺審核通過&#xff0c;前臺就可以展示&#xff0c;非常不錯的游戲發布平臺

一個項目學習Vue3---響應式基礎

觀察下面一段代碼&#xff0c;學習響應式基礎的全部內容 <template><div><div>將下面的msg屬性放到上面來:{{ msg }}</div><button click"count">{{ count }}</button><button click"object.count.value">{{ o…