摘要:計(jì)算機(jī)算法理論簡介建立初始堆首末元素互換即得到最大元素放入數(shù)組最末尾調(diào)整堆第二步的操作明顯會(huì)將堆破壞所以需要調(diào)整堆跳回第二步建立初始堆在建堆之前需要將數(shù)組轉(zhuǎn)成二叉樹圖方便理解如果將父左子右子當(dāng)做樹的最小單元組稱為父子單元那么只需要保證每個(gè)父
@(Study)[計(jì)算機(jī), 算法]
理論簡介建立初始堆
首末元素互換, 即得到最大元素放入數(shù)組最末尾.
調(diào)整堆. 第二步的操作明顯會(huì)將堆破壞, 所以需要調(diào)整堆.
跳回第二步.
建立初始堆在建堆之前需要將數(shù)組轉(zhuǎn)成二叉樹圖, 方便理解:
如果將父>左子|右子當(dāng)做樹的最小單元組, 稱為父子單元, 那么只需要保證每個(gè)父子單元滿足最大堆規(guī)則, 那么整體樹就滿足了最大堆.
==>定義一個(gè)方法(unitAdjust())用來調(diào)整父子單元, 將單元中最大的值推到該單元的根部, 成為父, 原來的父降到最大值之前的位置, 作為子. 但是這樣有可能使得以這個(gè)新子為父結(jié)點(diǎn)的下一層的父子單元不滿足最大堆規(guī)則. ==>設(shè)置規(guī)則, 如果發(fā)生了交換, 則遞歸調(diào)用方法自身, 調(diào)整新子為父結(jié)點(diǎn)的父子單元. 如此反復(fù).
上述過程可以說是自上而下的下鉆過程.
但是如果使得整個(gè)樹成為最大堆, 那么就是需要針對(duì)樹中的每個(gè)父子單元進(jìn)行調(diào)整. 只需要對(duì)樹中的每個(gè)非葉子節(jié)點(diǎn)進(jìn)行遍歷, 使用上述方法unitaAdjust()調(diào)整即可. 進(jìn)一分析, 可以發(fā)現(xiàn)這里有個(gè)問題: 遍歷的方向是自上而下還是自下而上呢?
如果自上而下會(huì)出現(xiàn)什么情況呢?
如下圖, 第一趟循環(huán)中, 操作的對(duì)象是以根結(jié)點(diǎn)34為父結(jié)點(diǎn)的父子單元. 循環(huán)體內(nèi)部將調(diào)用unitAdjust(), 34和50將互換, 由于發(fā)生了交換, unitAdust()方法將發(fā)生遞歸調(diào)用, 去操作以新子34為父結(jié)點(diǎn)的父子單元, 經(jīng)過比較, 未發(fā)生交換情況, 第一趟循環(huán)結(jié)束. 圖中發(fā)生了比較或者互換的位置以綠色標(biāo)出, 這時(shí)聰明的你不難發(fā)現(xiàn), 當(dāng)程序向下遍歷走到第三個(gè)節(jié)點(diǎn)時(shí), 便發(fā)生了重復(fù)比較, 當(dāng)然你或許能夠想到規(guī)避重復(fù)比較的方法, 但是我是沒有想出, 或者也可以認(rèn)為重復(fù)比較無所謂.
其實(shí), 換一種思路, 進(jìn)行自下而上遍歷情況就完全不一樣了.
從最后一個(gè)非葉子節(jié)點(diǎn)67開始, 67?90
50節(jié)點(diǎn)不動(dòng)
23?90, 觸發(fā)下鉆機(jī)制.
23?67
34?90, 觸發(fā)下鉆機(jī)制
34?67, 再次下鉆
未動(dòng)
最終得到初始堆如下圖所示, 其中藍(lán)色表示交換過位置.
可見, 整體是自下而上遍歷, 具體單元操作時(shí)采取自上而下, 總之, 自上而下和自下而上的相結(jié)合.
建立堆的過程其實(shí)有點(diǎn)冒泡的味道, 數(shù)值大逐漸的冒到上面, 好像密度大的即使開始在水底部, 但隨著遍歷, 密度大的終將上浮到上部.
堆排序初始堆建立好了后, 堆頂?shù)脑刈匀痪褪亲畲笾? 于是將第一個(gè)元素和最后一個(gè)元素互換, 即完成將最大值放到最末尾, 完了第一次排序.
由于交換使得堆被破壞, 所以需要對(duì)的n-1個(gè)元素進(jìn)行調(diào)整, 使其成為堆. 具體做法就是調(diào)用unitAdjust()對(duì)以根節(jié)點(diǎn)為父結(jié)點(diǎn)的父子單元進(jìn)行調(diào)整, 剛換來的最末位元素自然會(huì)被移到子節(jié)點(diǎn)位置, 這樣遞歸調(diào)用機(jī)制被觸發(fā), 于是繼續(xù)保證所有下層調(diào)整為堆.
接著將倒數(shù)第二個(gè)元素和堆頂元素互換, ......如此反復(fù).
代碼實(shí)現(xiàn)思路:
//建立初始堆// for (i=n/2;i>=1;i--) { unitAdjust() } //堆排序// for (i=n; i>=1; i--) { 首末交換 unitAdjust()調(diào)整 }
Java代碼:
測(cè)試結(jié)果:
10億長度, 內(nèi)存爆掉;
1億長度, 35693ms.
package LearningLog; /* * - 10億長度, 內(nèi)存爆掉 * - 1億長度, 35693ms. */ public class demo25 { public static void main(String[] args) { int[] arr=MyJava.randomArr(100000000, 10000,123); // System.out.println(Arrays.toString(arr)); // initHeap(arr); long t0 = System.currentTimeMillis(); heapSort(arr); long t1 = System.currentTimeMillis(); System.out.println((t1-t0)+"ms"); // System.out.println(Arrays.toString(arr)); } /* ====unitAdjust()=========================================== * 父子單元調(diào)整 * I: 父結(jié)點(diǎn)的索引, 數(shù)組長度: 非常非常非常關(guān)鍵, 因?yàn)楹罄m(xù)調(diào)用的時(shí)候, 需要卡住最大的遍歷位置, 否則將會(huì)將尾部已經(jīng)排好序的較大數(shù)值頂?shù)缴厦嫒チ? 那就糟糕嘔吐了 */ public static void unitAdjust(int array[],int fatherNode, int sub_size) { int lchild = 2*fatherNode+1; int rchild = lchild+1; int max = fatherNode; // 默認(rèn)最大值索引就是父結(jié)點(diǎn)的索引 int tmp = 0; if (fatherNode=0; i--) { unitAdjust(array, i, array.length); //大的值不斷上浮 } } /* * ====heapSort()================================================= * 堆排序 */ public static void heapSort(int[] array) { int tmp=0; //建立堆// initHeap(array); for(int i=array.length-1; i>=0; i--) { //首尾互換/ tmp = array[i]; array[i] = array[0]; array[0] = tmp; //剩下的i-1個(gè)元素需要調(diào)整// unitAdjust(array, 0, i); //始終只用調(diào)整第一個(gè)父子單元即可 } } }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71219.html
摘要:之所以把歸并排序快速排序希爾排序堆排序放在一起比較,是因?yàn)樗鼈兊钠骄鶗r(shí)間復(fù)雜度都為。歸并排序是一種穩(wěn)定的排序方法。因此,快速排序并不穩(wěn)定。希爾排序思想先將整個(gè)待排序的記錄序列分割成為若干子序列。 showImg(https://segmentfault.com/img/bVbvpYZ?w=900&h=250); 1. 前言 算法為王。 想學(xué)好前端,先練好內(nèi)功,只有內(nèi)功深厚者,前端之路才...
摘要:前面介紹了七大算法的思想與實(shí)現(xiàn)步驟,下面來做一個(gè)歸總。直到無序區(qū)中的數(shù)為零,結(jié)束排序。步驟以從小到大為例,排序數(shù)組大小為。比較完以后則排序結(jié)束。堆排序思想堆排序是采用樹的形式的數(shù)據(jù)結(jié)構(gòu)來進(jìn)行排序的,其中每一個(gè)堆都是完全二叉樹。 前面介紹了七大算法的思想與實(shí)現(xiàn)步驟,下面來做一個(gè)歸總。 排序方法 平均復(fù)雜度 最壞復(fù)雜度 最好復(fù)雜度 輔助空間 穩(wěn)定性 直接選擇排序 O(n^2...
摘要:一堆排序介紹來源百度百科堆排序是指利用堆積樹堆這種數(shù)據(jù)結(jié)構(gòu)所設(shè)計(jì)的一種排序算法,它是選擇排序的一種。 一、堆排序介紹 來源百度百科: 堆排序(Heapsort)是指利用堆積樹(堆)這種數(shù)據(jù)結(jié)構(gòu)所設(shè)計(jì)的一種排序算法,它是選擇排序的一種。可以利用數(shù)組的特點(diǎn)快速定位指定索引的元素。堆分為大根堆和小根堆,是完全二叉樹。 前面我已經(jīng)有二叉樹入門的文章了,當(dāng)時(shí)講解的是二叉查找樹,那上面所說的完全二...
摘要:奇妙的記憶點(diǎn)不穩(wěn)定內(nèi)排序基本思想分為兩步建堆與維持堆的性質(zhì)首先我們要先理解堆是什么東西堆其實(shí)就是一個(gè)完全二叉樹我們可以使用順序表存儲(chǔ)一個(gè)二叉樹如下圖所示來存儲(chǔ)其中分為最大堆最小堆而最大堆就是上頭大下頭小最小堆則反之明白了堆的定義我們就可以開 奇妙的記憶點(diǎn): 不穩(wěn)定 內(nèi)排序 基本思想: 分為兩步,建堆與維持堆的性質(zhì),首先我們要先理解堆是什么東西.堆其實(shí)就是一個(gè)完全二叉樹,我們可以使用...
摘要:當(dāng)?shù)竭_(dá)時(shí)等同于直接插入排序,此時(shí)序列已基本有序,所有記錄在統(tǒng)一組內(nèi)排好成有序序列。當(dāng)面對(duì)大量數(shù)據(jù)時(shí),希爾排序?qū)⒈戎苯硬迦肱判蚋邇?yōu)勢(shì)圖示講解第一趟取增量,所有間隔為的元素分在一組,在各個(gè)組中分別進(jìn)行直接插入排序。 ...
閱讀 3169·2021-10-12 10:11
閱讀 1877·2021-08-16 10:59
閱讀 2886·2019-08-30 15:55
閱讀 1254·2019-08-30 14:19
閱讀 2064·2019-08-29 17:03
閱讀 2499·2019-08-29 16:28
閱讀 3246·2019-08-26 13:47
閱讀 2918·2019-08-26 13:36