堆:通常是乙個可以被看做一棵完全二叉樹的陣列物件。實際中也通常用陣列來實現。(下面也都是基於陣列來進行討論的)
堆的定義
完全二叉樹要麼是滿二叉樹,若不滿,則在最後一層是從左往右依次補齊的。
堆可以分為:大根堆 和 小根堆兩種。
大根堆指:在這棵完全二叉樹中,任何一棵子樹的最大值都在子樹的頭節點;
小根堆相反。
接下來就是堆排序的過程:(以大根堆為例)
1、首先來看乙個函式 heapinsert:heapinsert(int arr, int i)表示在乙個大根堆末尾 i 處插入節點後,仍維持乙個0~i 的大根堆。
根據大根堆的定義:所有子樹都是頭節點最大,所以我們可以知道:當在末尾插入乙個節點時,需要與其所在子樹的頭節點進行比較,若插入節點大於頭節點,則需要將兩者進行交換;若發現交換後的頭節點仍然小於目前子樹的頭節點,繼續交換…直到小於所在子樹小於頭節點或者到頂了。很明顯,插入資料後維持大根堆是乙個資料不斷上浮的過程。 另外需要補充:若已知乙個完全二叉樹的頭節點在陣列中的索引為index,那麼可以直到其左、右子節點(若存在)的索引為:2 * index + 1 與 2 * index + 2。其父節點的索引為:(index - 1)/2。
接下來,依據這個函式可以很順利地建立乙個大根堆。從下標0開始不斷插入資料(呼叫heapinsert函式),直到陣列最後乙個元素,最終可以形成乙個大根堆。
//交換陣列中兩個位置的數
void
swap
(int arr,
int a,
int b)
//heapinsert函式
void
heapinsert
(int arr,
int index)
}//建立大根堆,其中len表示傳入的陣列的長度
void
makeheap
(int arr,
int len)
}
2、接下來看另外乙個函式heapify:heapify(int arr, int index, int heapsize)表示大根堆中索引為 index 的值變小了,仍然維持大根堆的過程。
試想根據大根堆的定義,若其中乙個節點的值變小了,仍要維持乙個大根堆,我們需要考慮,該節點的左右子節點(若存在)是否比現在的頭節點大,若子節點更大,我們就需要調整,然後迴圈這種比較,直到所變小的節點沉到最底部 或者 沒有子節點比它更大的時候,我們就維持好了乙個大根堆。
過程如下:
void
heapify
(int arr,
int index,
int heapsize)
}
至此我們已經知道了在大根堆中乙個值變小後仍然維持大根堆的過程。
前面鋪墊了這麼長,重點的堆排序怎麼做到呢?
過程如下:
1、先建立乙個大根堆;
2、將堆頂元素與最後乙個元素互換,將heapsize - 1;(相當於頭節點變小了,可以呼叫heapify函式維持大根堆)
3、維持heapsize - 1 大小的大根堆(即將最大元素換到最後,然後下次排序不考慮這個數了,只對堆中剩下的元素進行排序)。
4、迴圈2~3過程,直到所有元素排完。
void
heapsort
(int arr,
int len)
}int
main()
;int len =
sizeof
(array)
/sizeof
(array[0]
);heapsort
(array, len)
;for
(int i =
0; i < len; i++
)}
至此,整個堆排序就完成了,相信經過這一整個流程,大家會對堆排序有更深的理解了。 排序詳解 堆排序
堆排序 heapsort 是指利用堆積樹 堆 這種資料結構所設計的一種排序演算法,它是選擇排序的一種。可以利用陣列的特點快速定位指定索引的元素。堆分為大根堆和小根堆,是完全二叉樹。大根堆的要求是每個節點的值都不大於其父節點的值,即a parent i a i 在陣列的非降序排序中,需要使用的就是大根...
堆排序詳解
一 堆的定義 堆的定義如下 n個關鍵字序列l n 成為堆,當且僅當該序列滿足 l i l 2i 且l i l 2i 1 或者 l i l 2i 且l i l 2i 1 其中i屬於 1,n 2 滿足第 種情況的堆稱為小根堆 小頂堆 滿足第 種情況的堆稱為大根堆 大頂堆 在大根堆中,最大元素存放在根結點...
堆排序詳解
public class heapsort 此時已經完成了最大堆的構建,下面進行排序。for int i len 1 i 0 i 維護最大堆,保證父節點大於等於子節點 public static void maxheapify int a,int index,int len if rightchil...