堆排序運用到了樹的思想。它仍然使用陣列排序,並不建立樹,但是排序時將陣列看作乙個完全二叉樹,通過不斷地構建大頂堆,將樹頂元素與樹尾元素交換,以樹頂構建新的大頂堆來把整個陣列從小到大排序。
首先,將數字按從上到下,從左到右的順序寫成一顆完全二叉樹,這樣的樹的特點是,對於父節點i(對應陣列中的下標i),它的左子節點的陣列下標為2*i+1,右子節點的陣列下標為2*i+2。而最下面的非葉子節點的陣列下標為arr.length/2-1
進行堆排序大致分為兩步,第一步是構建大頂堆,第二步是樹頂元素與末尾元素交換。
首先,大頂堆是指:每個結點的值都大於或等於其左右孩子結點的值,稱為大頂堆。小頂堆是指:每個結點的值都小於或等於其左右孩子結點的值,稱為小頂堆。對陣列公升序排列要構建大頂堆,而降序排列要構建小頂堆。
構建大頂堆:
這個方法用來將以乙個非葉子節點開始的子樹構建成大頂堆,需要三個變數,陣列arr,該非葉子節點的陣列下標i,和要改變的最大元素數(一開始就是陣列的長度,每次排好了乙個元素時就不用再去改變它,所以排列時每次會減1)
首先用temp儲存這個非葉子節點的值。這個值中途是不會改變的,實際上,我們就是需要把它放在合適的位置上。
然後用for迴圈來遍歷它的子樹,j用來指向子節點(j表示的陣列的下標),根據上面的性質j=2*i+1,當j小於length時,就可以不斷迴圈(一開始代表的是傳進來的這個非葉子節點的左子節點,之後會不斷指向子節點的子節點),這時,在兩個子節點中尋找較大的,並讓j指向大的那個數。j+1就代表右子節點,它同樣要小於length,防止出現越界,所以當右子節點較大時,讓j+1就行。完成後,j就指向了子節點中大的那個,這時判斷temp和arr[j]的大小,如果temp小,就把arr[j]賦給arr[i],並讓i=j,如果temp大,說明符合大頂堆的邏輯,直接break退出迴圈就好。
注意的是:temp的值是不變的,等於一開始的非葉子節點值,每次是用temp和arr[j]比較,而不是arr[i]和arr[j]比較,因為arr[i]的值是會變化的(一開始指向傳進來的非葉子節點,如果不是大頂堆,就會指向該節點較大的子節點,然後再指向子節點的子節點,不斷改變)而我們實際上是在為temp找乙個合適的位置,如果是arr[i]和arr[j]比較,就會出現temp小於arr[i]的情況,使得無法正確構建大頂堆,在這裡的賦值是不斷將較大的子節點賦給父節點。i=j這是讓i指向較大的子節點,也就是下一次迴圈中的父節點,也就是i永遠指向父節點,j永遠指向較大的子節點。至於敢於直接break,是因為我們一定是從最小的非葉子節點開始構建大頂堆,從右向左,從下到上,所以可以直接break,因為下面的構建總是正確的。
退出迴圈後,讓arr[i]等於temp,因為我們之前只是將較大的子節點賦給父節點,而子節點的值沒有改變,實際上,它們應該交換。此時i指向的就是temp合適的位置,也就是某個子節點或者就沒變,這時就直接賦值,完成交換。而這一步一定要放在迴圈外。因為迴圈內的i不一定是temp的合適位置。
/**
* 構建大頂堆
* @param arr 原陣列
* @param i 構建大頂堆的最頂的非葉子節點的下標
* @param length 要調整的最大元素數,每次不斷減少
*/public
static
void
adjustheap
(int
arr,
int i,
int length)
if(temp
)else
} arr[i]
=temp;
}
排序方法的思路:首先呼叫上面的方法將原陣列構建成大頂堆。這時因為上面的邏輯,要保證一定要從最後乙個非葉子節點開始,逐漸向上。所以先求出下標,然後- -。完成後,顯然根節點就是陣列中最大的數了,讓它與陣列末尾數交換,那麼最大的數就放在最後了,這時新的根節點不一定是陣列中最大的,所以就以它為頭,重新構建大頂堆(因為實際上只改變了兩個數,而移下去的最大數不參與排列新大頂堆,也就是下面的大頂堆邏輯並沒有被破壞,所以不用迴圈,而直接排就可以),然後重複這個過程,直到排列完畢。
public
static
void
heapsort
(int
arr)
//交換
for(
int i = arr.length-
1; i >
0; i--
)}
堆排序學習筆記
參考此文的學習筆記 不用交換,則已經是最大堆,不用迴圈了 else break void sort int a,int length 開始排序,排序是從上到下從左到右的調整 for int j length 1 j 0 j int main sort a,length for int i 0 i l...
堆排序學習筆記
堆排序 利用帶大頂堆的特點 從小到大時 按照從右向左 從下自上的順序將所有的非葉子節點都調整成以當前非葉子節點為根的大頂堆,這樣遍歷完成之後,整棵樹就變成了乙個大頂堆,最大的元素在根節點上,這時將這個最大的元素和最後乙個位置上的元素進行交換,這樣最大值就跑到了最後,這樣操作之後,由於整棵樹原本就是大...
筆記 堆排序
堆排序只需要記錄乙個記錄大小的輔助空間,每個待排序的記錄僅占有乙個儲存空間。堆的定義 n個元素的序列 當且僅當滿足如下關係時,稱之為堆。ki k2ik i k2 i 1 或 ki k 2iki k2i 1 i 1,2,3,n 2 若將和此序列對應的一維陣列看成是乙個完全二叉樹,則堆的含義表明,完全二...