日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【算法知识】详解堆排序算法

發布時間:2025/3/8 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【算法知识】详解堆排序算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

點擊藍色字關注我們!

什么是堆

「堆」首先是一個完全二叉樹,「堆」分為「大頂堆」「小頂堆」
「大頂堆」 :
每個節點的值大于或等于其左右孩子節點的值,稱為大頂堆。
「小頂堆」同理就是每個節點的值小于或等于其左右孩子節點的值。
「注意」:
每個節點的左右孩子節點的大小關系并沒有限定。

大頂堆舉例

如圖:

大頂堆舉例

首先其為一個完全二叉樹,且其每個節點的值都大于或者等于其左右孩子節點的值。
完全二叉樹從上到下,從左到右依次編號,就可以將其進行順序存儲,我們從根節點開始,從0開始編號,存入數組如下:

大頂堆存入數組舉例

堆特點

由大頂堆定義知道,如果我們從上到下,從左到右,根節點開始從0編號進行順序存儲的話,并將數組記為arr;
我們可以得到如下式子:
arr[i] >= arr[ 2i + 1] ?&& arr[ i ] >= arr[ 2i + 2];
其中 2i + 1為第 i 個節點的左孩子節點的編號。2i + 2為第 i 個節點的右孩子節點的編號;
同理得小頂堆的特點:
arr[i] <= arr[ 2i + 1] ?&& arr[ i ] <= arr[ 2i + 2];

堆排序基本思想

本文以大頂堆為例,進行講解。
算法步驟如下:
1、首先將待排序序列構建成一個大頂堆(存入數組中),那么這時,整個序列的最大值就是堆頂的根節點;
2、將堆頂元素與最后一個元素交換,那么末尾元素就存入了最大值;
3、將剩余的 n - 1個元素重新構建成一個大頂堆,重復上面的操作;
反復執行,就能得到一個有序序列了。

舉例

給定一個待排序序列數組 arr = [ 0 , 2, ?4, ?1 , 5 ];
先構建成一個完全二叉樹如下;

初始狀態

構建堆

「我們從最后一個非葉子節點開始,從左至右,從下到上,開始調整」
最后一個非葉子節點的索引即 arr.length / 2向下取整 - 1 ,對于此例就是 5 / 2向下取整 - 1 = 2 - 1 = 1;
即值為2的節點;

構建堆1

我們用左右孩子節點的最大值與該節點進行比較;
此時我們發現它的左右孩子節點的最大值為5,大于2,進行交換;

構建堆2

然后處理下一個非葉子節點,即剛才的索引減去1;1 - 1 = 0;
即:

構建堆3

左右孩子節點為5和4,5最大,且大于該節點的值,發生交換;

構建堆4

這時我們發現了一個問題:
「值為0的節點的左右節點又比該節點大了,又不滿足大頂堆的定義了」

繼續進行調整:

構建堆5

對非葉子節點調整完畢,構建大頂堆完成。

交換

將堆頂元素與末尾元素進行交換,使得末尾元素最大。

堆頂元素與末尾元素交換

當交換完畢后最大的元素已經到達數組末尾;

第一次交換后

對數組中其他元素進行排序即可。

剩下的四個元素進行調整

進行交換:

第二大元素歸位

剩下的元素調整并交換后:

第三大元素歸位

剩下的元素調整并交換后:

第三大元素歸位第四大元素歸位置

此時也意味著排序完成了。

代碼

先說下調整的代碼;
我們需要三個參數,待排序的數組,數組的長度,還有一個就是調整的哪一個非葉子節點;

?/***?author:微信公眾號:code隨筆*?@param?arr?待排序的數組*?@param?i???表示等待調整的哪個非葉子節點的索引*?@param?length?待調整長度*/public?static?void?adjustHeap(int?arr[],int?i,int?length){//非葉子節點的值int?notLeafNodeVal?=?arr[i];//k的初始值為當前非葉子節點的左孩子節點的索引//k?=?2?*?k?+?1表示再往左子節點找for(int?k?=?i?*?2?+?1;k<length;k=2?*k?+?1){//如果k?+?1還在待調整的長度內,且右子樹的值大于等于左子樹的值//將k++,此時為當前節點的右孩子節點的索引if(k+1<length?&&?arr[k]?<?arr[k+1]){k++;}//如果孩子節點大于當前非葉子節點if(arr[k]?>?notLeafNodeVal){arr[i]?=?arr[k];//將當前節點賦值為孩子節點的值i?=?k;//將i賦值為孩子節點的值,再看其孩子節點是否有比它大的}else{break;//能夠break的保證是,我們是從左至右,從下到上進行調整的//只要上面的不大于,下面的必不大于}}//循環結束后,將i索引處的節點賦值為之前存的那個非葉子節點的值arr[i]?=?notLeafNodeVal;}

再說下堆排序代碼,看好注釋;

//堆排序方法public?static?void?heapSort(int?arr[]){//進行第一次調整for(int?i=arr.length/2?-?1;i>=0;i--){adjustHeap(arr,i,arr.length);}for(int?j=arr.length?-?1;j>0;j--){//進行交換int?temp?=?arr[j];arr[j]?=?arr[0];arr[0]?=?temp;//調整長度為j的那些//這里為什么填0呢//因為我們第一次調整的時候從左到右,從下到上調整的;//交換時只是變動了堆頂元素和末尾元素//末尾元素我們不用去管,因為已經是之前長度最大的了//只需要把當前堆頂元素找到合適的位置即可adjustHeap(arr,0,j);}}

完整代碼

import?java.util.Arrays;public?class?Solution?{public?static?void?main(String[]?args)?{int?[]?arr?=?new?int[]{0?,?2,??4,??1?,?5};heapSort(arr);System.out.println(Arrays.toString(arr));}//堆排序方法public?static?void?heapSort(int?arr[]){//進行第一次調整for(int?i=arr.length/2?-?1;i>=0;i--){adjustHeap(arr,i,arr.length);}for(int?j=arr.length?-?1;j>0;j--){//進行交換int?temp?=?arr[j];arr[j]?=?arr[0];arr[0]?=?temp;//調整長度為j的那些//這里為什么填0呢//因為我們第一次調整的時候從左到右,從下到上調整的;//交換時只是變動了堆頂元素和末尾元素//末尾元素我們不用去管,因為已經是之前長度最大的了//只需要把當前堆頂元素找到合適的位置即可adjustHeap(arr,0,j);}}/***?author:微信公眾號:code隨筆*?@param?arr?待排序的數組*?@param?i???表示等待調整的哪個非葉子節點的索引*?@param?length?待調整長度*/public?static?void?adjustHeap(int?arr[],int?i,int?length){//非葉子節點的值int?notLeafNodeVal?=?arr[i];//k的初始值為當前非葉子節點的左孩子節點的索引//k?=?2?*?k?+?1表示再往左子節點找for(int?k?=?i?*?2?+?1;k<length;k=2?*k?+?1){//如果k?+?1還在待調整的長度內,且右子樹的值大于等于左子樹的值//將k++,此時為當前節點的右孩子節點的索引if(k+1<length?&&?arr[k]?<?arr[k+1]){k++;}//如果孩子節點大于當前非葉子節點if(arr[k]?>?notLeafNodeVal){arr[i]?=?arr[k];//將當前節點賦值為孩子節點的值i?=?k;//將i賦值為孩子節點的值,再看其孩子節點是否有比它大的}else{break;//能夠break的保證是,我們是從左至右,從下到上進行調整的//只要上面的不大于,下面的必不大于}}//循環結束后,將i索引處的節點賦值為之前存的那個非葉子節點的值arr[i]?=?notLeafNodeVal;} }

時間復雜度

在建初始堆時,其復雜度為;
交換操作需 n-1 次;
重建堆的過程中近似為;
堆排序時間復雜度為。

穩定性

堆排序是不穩定的:
比如:10,9,6,9;如圖:

穩定性分析用圖

當堆頂元素10和末尾元素交換后,兩個9的相對位置發生改變。

已發布:

【算法知識】詳解冒泡算法

【算法知識】詳解選擇排序算法

【算法知識】詳解插入排序算法

【算法知識】詳解快速排序算法

【算法知識】詳解基數排序算法

往期精彩回顧適合初學者入門人工智能的路線及資料下載機器學習及深度學習筆記等資料打印機器學習在線手冊深度學習筆記專輯AI基礎下載(pdf更新到25集)機器學習的數學基礎專輯本站qq群1003271085,加入微信群請回復“加群”獲取一折本站知識星球優惠券,復制鏈接直接打開:https://t.zsxq.com/yFQV7am喜歡文章,點個在看

總結

以上是生活随笔為你收集整理的【算法知识】详解堆排序算法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。