圖解堆排序【一眼看穿邏輯思路】

P. S.:以下代碼均在VS2019環境下測試,不代表所有編譯器均可通過。
P. S.:測試代碼均未展示頭文件stdio.h的聲明,使用時請自行添加。

??

目錄

  • 1、堆的概念
  • 2、實現堆排序前的準備工作
  • 3、堆排序的思路
    • 3.1 第一步
    • 3.2 第二步
  • 4、結語

1、堆的概念


??在了解堆排序之前我們先要了解什么是堆:一個按照完全二叉樹的儲存方式存儲的一維數組我們稱之為堆。


在這里插入圖片描述


??而堆又可以分為大堆和小堆。
??大堆:二叉樹中的父結點在數值上都比子結點大。
??小堆:二叉樹中的父結點在數值上都比子結點小。
??下圖在就是一組較為明顯的大小堆。

在這里插入圖片描述

??故堆排序就是在堆的前提下進行排序。




2、實現堆排序前的準備工作


??我們需要完成的準備工作是實現一個關于二叉樹即堆的向下調整函數,此處我們寫為HeapAdjustDown。
void Swap(int* p1,int* p2) //簡單的交換函數
{int* tmp = *p1;*p1 = *p2;*p2 = tmp;
}void HeapAdjustDown(int* a,int n,int parent)//a代表數組的地址,n為數組元素個數,parent為當前元素所在下標。
{int child = parent * 2 + 1;		//假設左孩子大于或小于右孩子.while(child < n)				//結束條件為到達最后一層時,最后一層沒有子。{if(child + 1 < n && a[child + 1] > a[child])//判斷左孩子是否真的大于或小于右孩子,如果不是{											//讓child代表右邊孩子的下標。++child;}if(a[child] > a[parent])	//判斷父與子的關系,如果父大于或小于子,讓其交換位置。{Swap(&a[child],&a[parent])parent = child;			//此處令交換的子的下標成為新的parent下標,即沿著交換路徑一致進行//比較,直至到達最后一層。child = parent * 2 + 1;}else{break;					//當不滿足大小條件是就會進來,即已經按照需求將堆排列成了大堆或者小堆。}}
}

??上面就是我們所完成的準備工作,其中
if(child + 1 < n && a[child + 1] < a[child])
if(a[child] < a[parent])

??這兩條判斷語句中的數組內成員比較可以更換比較符號。
??當使用 “ < ” 號時,第一條判斷依據所篩選的時兩個子中較小的一個。
?????????? 第二條判斷語句就是比較所選的子是否小于父,如果小于就進行交換。
?????????? 這樣進行調整后的堆就稱之為小堆,即父皆比子小。
??當使用 “ > ” 號時,第一條判斷依據所篩選的時兩個子中較大的一個。
?????????? 第二條判斷語句就是比較所選的子是否大于父,如果大于就進行交換。
?????????? 這樣進行調整后的堆就稱之為大堆,即父皆比子大。




3、堆排序的思路


3.1 第一步


??我們首先要做的就是將得到的數組進行調整,將其調整為大堆或者小堆。
??故寫一個函數來進行操作較為方便:HeapSort
void HeapSort(int* a,int n)//此處的n為數組的元素個數
{for(int i = (n - 1 - 1) / 2; i >= 0; i--)//此處為何從(n - 1 - 1) / 2開始,后面會有圖解,耐心一點哦~{//然后調用我們的向下調整函數。HeapAdjustDown(a,n,i);}
}

??到這里后,我們就完成了對數組的大堆或者小堆化,此處我們所進行的是大堆化處理。
??下面就進行我們此截止到目前的看圖說話:
??假設我們所擁有的數組是{1,3,5,7,9,2,4,6,8,10}。
在這里插入圖片描述??其在數組中和在堆中的存放方式如上圖所示,我們按照上述代碼執行。
在這里插入圖片描述
??而后我們在數組元素9的基礎上進行向下調整。
在這里插入圖片描述
??這一步進行完后,我們的i–,此時的i = 3,也就是我們的元素7所在下標,故此時在數組元素7的基礎上向下調整。
在這里插入圖片描述
??故循環的意義就是從最后一層的父開始進行向下調整,一致循環到根位置,后面我們直接展示過程圖,不在進行比較講解。
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
??到此處我們的大堆構建也算完成了。
在這里插入圖片描述
??根據VS驗證我們所進行的數組大堆化也是正確無誤的。
??此處又會有看官提出問題,我們為什么不從數組的頭部開始進行向下調整呢,反而從尾部開始呢?
在這里插入圖片描述
??我們直接上圖,當我們從頭部開始時,進行向下調整,得到的卻不是大堆。這是因為:
在這里插入圖片描述
??而后我們也同樣直接展示過程圖:
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
??至此我們所得到的新數組也就和上述實驗數組結果一致,為{5,9,4,8,10,2,1,6,7,3}。
??總而言之,我們不從頭部開始進行向下調整,是因為以這樣的方式進行時,每一次調整只會調整當前位置及當前位置向后的數據,而不會向前進行比較,會造成不可避免地bug。


3.2 第二步


??我們將數組大堆或小堆化后,就可以進行排序了,此時我們進行的是升序排列,排序的代碼如下:
void HeapSort(int* a,int n)//此處的n為數組的元素個數
{for(int i = (n - 1 - 1) / 2; i >= 0; i--)//此處為何從(n - 1 - 1) / 2開始,后面會有圖解,耐心一點哦~{//然后調用我們的向下調整函數。HeapAdjustDown(a,n,i);}int end = n - 1;		//原理下文解釋while(end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);--end;}
}

??我們可以看到代碼中創建了一個變量 “ end ”,其代表的含義為最后一個元素的數組下標,我們在前文中已經將數組進行了大堆化,故我們數組的第一個元素是大于其他元素的。
在這里插入圖片描述
??此時我們將第一個數和最后一個數據交換位置,這樣最大的數就處在了末尾,然后按照同樣的方式對前面九個數字進行大堆化,這樣就又會有一個第二大的數字排列在第一位,然后進行下一次循環,然后我們將 end–,進入下一次循環。下面我們展示過程圖,并不在對途中內容進行講解:
在這里插入圖片描述
在這里插入圖片描述
在這里插入圖片描述
??依次向下進行最終就得到了如下的數組。
在這里插入圖片描述

在這里插入圖片描述
??通過驗證我們可以得到上述方法是可行且正確無誤的。
??從中我們也可以發現一個規律,我們通過創建大堆可以得到升序的序列,通過類比,我們明白也可以通過創建小堆可以得到降序的序列。




4、結語


??十分感謝您觀看我的原創文章。
??本文主要用于個人學習和知識分享,學習路漫漫,如有錯誤,感謝指正。
??如需引用,注明地址。

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

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

相關文章

音視頻捕捉技術:LCC382 SDI采集卡深度解析

在日新月異的多媒體時代&#xff0c;高質量的音視頻采集已成為眾多領域不可或缺的一環。為此&#xff0c;靈卡科技精心打造了LCC382 —— 一款集高效性、靈活性與前沿技術于一身的SDI輸入與環出、HDMI輸出音視頻采集卡&#xff0c;旨在滿足從專業直播、視頻會議到醫療影像、安防…

網頁版Figma漢化

最近學習Figma&#xff0c;簡單介紹一下網頁版Figma的漢化方法 1.打開網址&#xff1a;Figma軟件漢化-Figma中文版下載-Figma中文社區 2.下載漢化插件離線包 解壓漢化包 3.點開谷歌的管理擴展程序 4.點擊加載已解壓的擴展程序&#xff0c;選擇剛剛解壓的包 這樣就安裝好了漢化…

QT狀態機2-含終止狀態的嵌套狀態機

#include "MainWindow.h" #include "ui_MainWindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent)

前饋神經網絡FNN、多層感知機MLP和反向傳播推導

目錄 一、前饋神經網絡FNN 激活函數的使用 二、多層感知機MLP MLP的典型結構 多層感知機MLP的特點 和前饋神經網絡FNN的區別 三、傳播推導 1、前向傳播(Forward propagation) &#xff08;1&#xff09;輸入層到隱藏層 &#xff08;2&#xff09;隱藏層到輸出層 2、…

Java面試八股之WeakHashMap的工作原理

簡述WeakHashMap的工作原理 弱鍵&#xff08;Weak Keys&#xff09;&#xff1a; WeakHashMap 的鍵&#xff08;keys&#xff09;是通過 WeakReference 弱引用進行封裝的。弱引用是一種特殊的引用類型&#xff0c;它不會阻止所引用的對象被垃圾收集器回收。這意味著&#xff…

冥想訓練具體方法有哪些|流靜冥想

冥想是一種身體的放松和敏銳的警覺性相結合的狀態。 每日練習的好處遠不止你花在集中注意力的那幾分鐘。桑托雷利是建在烏斯特的馬薩諸塞大學醫學院的減壓診所的所長&#xff0c;她也是《自愈》的作者&#xff0c;她說&#xff1a;"冥想是一種工具&#xff0c;通過練習&a…

ubuntu無法遠程連接,ssh不可用,ssh遠程連接被拒絕的解決方法。啟動sshd遠程連接

1、用以下命令檢查ssh狀態 systemctl status sshd2、如果查不到sshd狀態&#xff0c;或提示沒有ssh&#xff0c;就安裝ssh服務器和客戶機 $ sudo apt install openssh-server # 安裝ssh服務器 $ sudo apt install openssh-client # 安裝ssh客戶機3、如果不能安裝openssh-…

構建安全的GenAI/LLMs核心技術解密之大模型對抗攻擊(一)

LlaMA 3 系列博客 基于 LlaMA 3 + LangGraph 在windows本地部署大模型 (一) 基于 LlaMA 3 + LangGraph 在windows本地部署大模型 (二) 基于 LlaMA 3 + LangGraph 在windows本地部署大模型 (三) 基于 LlaMA 3 + LangGraph 在windows本地部署大模型 (四) 基于 LlaMA…

云手機的優缺點分析

云手機&#xff0c;作為云計算領域的創新&#xff0c;致力于提供更為靈活的移動設備體驗&#xff0c;特別適用于那些希望在不同設備之間無縫切換的用戶。雖然云手機帶來了一系列優勢&#xff0c;但也伴隨著一些挑戰&#xff0c;比如網絡延遲可能會影響用戶體驗&#xff0c;特別…

網絡安全|隱藏IP地址的5種不同方法

隱藏計算機的IP地址在互聯網在線活動種可以保護個人隱私&#xff0c;這是在線活動的一種常見做法&#xff0c;包括隱私問題、安全性和訪問限制內容等場景。那么如何做到呢?有很5種方法分享。每種方法都有自己的優點和缺點。 1. 虛擬網絡 當您連接到虛擬服務器時&#xff0c;您…

openGauss學習筆記-284 openGauss AI特性-AI4DB數據庫自治運維-DBMind模式說明-component子命令

文章目錄 openGauss學習筆記-284 openGauss AI特性-AI4DB數據庫自治運維-DBMind模式說明-component子命令284.1 命令參考openGauss學習筆記-284 openGauss AI特性-AI4DB數據庫自治運維-DBMind模式說明-component子命令 該子命令可以用于啟動DBMind的組件,包括可用于監控指標的…

Dubbo配置上的一些概念

對于dubbo在spring中我們可能看到有如下配置&#xff08;可參考Schema 配置參考手冊 | Apache Dubbo&#xff09;&#xff1a; dubbo:application:id: dubbo-account-examplename: dubbo-account-example# 是否啟用 Dubbo 的 QoS&#xff08;Quality of Service&#xff09;服…

Blender雕刻建模_筆刷

1.雕刻模式 雕刻Scuplt&#xff0c;一種常用的建模方式 -選中物體&#xff0c;進入雕刻模式 -重構網格&#xff08;修改體素大小&#xff0c;點擊重構網格&#xff09;給物體添加更多面 -選擇筆刷&#xff0c;雕刻 -退出雕刻模式 2.重構網格 一種按體積的細分方式&#xf…

openstack部署nova中出現的問題:

[rootcontroller nova]# su -s /bin/sh -c “nova-manage db sync” nova /usr/lib/python2.7/site-packages/pymysql/cursors.py:170: Warning: (1831, u’Duplicate index block_device_mapping_instance_uuid_virtual_name_device_name_idx. This is deprecated and will be…

Springboot+MybatisPlus如何實現帶驗證碼的登錄功能

實現帶驗證碼的登錄功能由兩部分組成&#xff1a;&#xff1a;1、驗證碼的獲取 2、登錄&#xff08;進行用戶名、密碼和驗證碼的判斷&#xff09; 獲取驗證碼 獲取驗證碼需要使用HuTool中的CaptchaUtil.createLineCaptcha()來定義驗證碼的長度、寬度、驗證碼位數以及干擾線…

【JavaScript】嚴格模式

嚴格模式&#xff08;Strict Mode&#xff09;是一種運行模式&#xff0c;它提供了一種更加嚴格的語法和錯誤檢查&#xff0c;以幫助開發者編寫更可靠、更規范的代碼。 什么是嚴格模式&#xff1a; 嚴格模式是一種 JavaScript 的執行模式&#xff0c;通過啟用嚴格模式&#xff…

這個notebook集合,贊

這幾天在Github上看到一個數據科學倉庫&#xff0c;匯總了很多Python notebook代碼&#xff0c;主要是數據方向。 項目地址&#xff1a; https://github.com/donnemartin/data-science-ipython-notebooks 其中包括了pandas、numpy、matplotlib、scikit-learn、tensorflow、sp…

【Xilinx】程序可以綜合實現,但無法生成bit文件

項目場景&#xff1a; 使用xilinx vivado過程中遇到以下問題&#xff1a; 程序可以綜合實現&#xff0c;但無法生成bit文件 問題描述 最終生成bit文件時報錯如下 [DRC PDCN-1567] BUFGCTRL_CE_pins_both_connected_to_gnd: For cell ***/rxrecclk_bufg_i placed at site BU…

c++ visualstudio2017 opencv debug源碼 windows配置

源碼下載和cmake opencv源碼和opencv-contribue文件夾的層級目錄 在opencv-4.4.0中新建build文件夾&#xff0c;并啟動cmake-gui 配置如下&#xff0c;使用vs2017 x64, 需要注意contrib文件夾的設置&#xff0c;如下方藍色所示&#xff0c;依次點擊Configure和Generate 在bu…

半小時搞懂STM32知識點——UART

1.UART 1.1為什么要使用UART這種協議?介紹一下UART及其特點 成本低&#xff0c;硬件簡單&#xff0c;數據格式靈活&#xff1b; 低速全雙工異步串行通信 1.2 UART數據幀格式&#xff1f; 起始位&#xff08;1&#xff09;&#xff0b;數據位&#xff08;5-8&#xff09; 校驗位…