排序(堆排序)

2021-09-28 19:34:50 字數 4415 閱讀 3190

堆排序基本介紹

堆排序用到了完全二叉樹的順序儲存結構(即陣列),所以順序儲存並不是完全無用,在這裡會發揮大作用。

tips:一定要理解大頂堆、小頂堆、完全二叉樹以及完全二叉樹的順序儲存結構才能理解堆排序,這個是前提喲!!!

圖1:大頂堆示例

圖2:小頂堆示例

堆排序基本思路

以公升序排序來講,先將陣列arr0 ~ arr.length-1)調整成乙個堆。

1.1 怎麼調整?從0~arr.length-1的元素中的最後乙個非葉子節點開始調整,這個葉子節點的下標是arr.length/2-1,設為x;

1.2 這個葉子節點的左子節點的下標2*x+1,設為leftchild;右子節點的下標識2*x+2,設為rightchild。然後比較arr[leftchild]arr[rightchild]的大小,假設arr[leftchild]更大,將arr[leftchild]再與arr[x]比較,如果arr[leftchild]>arr[x],將arr[leftchild]和arr[x]交換,使以x為根節點的這棵子樹滿足大頂堆的特點。

1.3x - -,重複1.2,直到x==0

將陣列arr調整成乙個大頂堆後,堆的根節點,即arr[0]是陣列中最大的那個數,將arr[0]與arr[length-1]交換,這時最大的元素就被交換到了陣列尾部。

交換了arr[0]與arr[length-1]後,原本調整好的堆的順序就亂了,所以需要重新調整以arr[0]作為根節點的樹,將其調整成乙個新得大頂堆,不過這時候參與調整的元素不在是0 ~ arr.length-1,而是0 ~ arr.length-2,因為此時陣列尾部已經是最大的那個數了,不需要在參加排序。重新調整成大頂堆後將arr[0]arr[length-2]交換。交換後原本調整好的堆結構又變化了,這時又重新調整以arr[0]為根節點的樹堆結構,不過參與調整的元素為0 ~ length-3,調整好後又交換arr[0]arr[length-3]。然後又以arr[0]為根節點調整成大頂堆…這樣不斷調整、交換、調整、交換,直到要參與調整的元素是0~0

介紹了這些,可能你還沒怎麼理解,建議自己寫幾個數來畫畫圖,結合下面的**,進一步理解堆排序,因為這的確不好說。

**實現

/**

* @author chenzhiyuan

* @date 2019-10-17 23:39

*/public

class

heapsort

for(

int i = nums.length -

1; i >

0; i--)}

/** * 將以nums[root]作為根節點的子樹調整為大頂堆

** @param nums 待排序的陣列

* @param root 表示當前要調整成大頂堆的子樹的根節點的下標,注意不一定是整個nums對應的樹的根,還可能是子樹的根

* @param length 參與調整的元素的個數,也就是思路介紹中第一次是對0~nums.length的元素調整,第二次是以0~nums.length-1的元素調整...

*/private

static

void

adjuctheap

(int

nums,

int root,

int length)

// 比較根節點和和nums[k]的大小

if(nums[k]

> nums[root]

)else}}

public

static

void

swap

(int

nums,

int i,

int j)

}

測試耗時
// 建立隨機數

public

static

int[

]createnum

(int size,

long seed)

return nums;

}// 測試5輪

public

static

void

testtime

(int size)

;int

nums =

createnum

(size, seeds[0]

);long start = system.

currenttimemillis()

;heapsort

(nums)

;long end = system.

currenttimemillis()

; system.out.

println

("耗時:"

+(end - start)

+"ms");

nums =

createnum

(size, seeds[1]

);start = system.

currenttimemillis()

;heapsort

(nums)

; end = system.

currenttimemillis()

; system.out.

println

("耗時:"

+(end - start)

+"ms");

nums =

createnum

(size, seeds[2]

);start = system.

currenttimemillis()

;heapsort

(nums)

; end = system.

currenttimemillis()

; system.out.

println

("耗時:"

+(end - start)

+"ms");

nums =

createnum

(size, seeds[3]

);start = system.

currenttimemillis()

;heapsort

(nums)

; end = system.

currenttimemillis()

; system.out.

println

("耗時:"

+(end - start)

+"ms");

nums =

createnum

(size, seeds[4]

);start = system.

currenttimemillis()

;heapsort

(nums)

; end = system.

currenttimemillis()

; system.out.

println

("耗時:"

+(end - start)

+"ms");

}

結果如下:

>二十萬資料

耗時:56ms

耗時:49ms

耗時:38ms

耗時:40ms

耗時:36ms

>一千萬資料

耗時:2037ms

耗時:1747ms

耗時:1937ms

耗時:1705ms

耗時:1703ms

堆排序 堆排序優化 索引堆排序

堆排序 堆排序優化 索引堆排序 注 堆排序 索引堆排序 都是不穩定的排序。注 索引最大堆排序有誤!有沒有大神可以指點一二?1 堆 所有元素 都從索引0開始 父親結點索引 i 左孩子結點索引 2i 1 右孩子結點索引 2i 2 左後乙個非葉子結點索引 n 1 2 用於構建堆,從最後乙個非葉子結點索引開...

堆排序 堆排序優化 索引堆排序

堆排序 堆排序優化 索引堆排序 注 堆排序 索引堆排序 都是不穩定的排序。注 索引最大堆排序有誤!有沒有大神可以指點一二?1 堆 所有元素 都從索引0開始 父親結點索引 i 左孩子結點索引 2i 1 右孩子結點索引 2i 2 左後乙個非葉子結點索引 n 1 2 用於構建堆,從最後乙個非葉子結點索引開...

堆排序 模擬堆排序

838.堆排序 輸入乙個長度為n的整數數列,從小到大輸出前m小的數。輸入格式 第一行包含整數n和m。第二行包含n個整數,表示整數數列。輸出格式 共一行,包含m個整數,表示整數數列中前m小的數。資料範圍 1 m n 1051 m n 105,1 數列中元素 1091 數列中元素 109 輸入樣例 5 ...