倍道而行 :堆(heap)
概念
先來兩個概念(別頭疼):
普通隊列:先進先出,后進后出
優(yōu)先隊列:出隊順序和入隊順序無關;和優(yōu)先級相關。就好比:我們的電腦操作系統(tǒng)會按照各個進程的優(yōu)先級來安排CPU執(zhí)行哪一個進程。
堆(heap)被稱為一種優(yōu)先隊列,但是堆的本質不是隊列。取出順序就是每次取最大的唄。
下圖就是一個堆:
本質就是一個完全二叉樹。完全二叉樹的定義看圖就可得出:父節(jié)點都大于等于子節(jié)點。且是從上大下,從左至右的排序。
堆的實現(xiàn)
看圖:
仔細看每個數(shù)的下標。數(shù)組是從1開始的。父節(jié)點和子節(jié)點的關系也可以很容易得出。
eg:41是28和16的父節(jié)點,下標分別為2、4、5,滿足圖中的公式。
如題:有10個數(shù),請用代碼將之組成一個堆?
算法思想:每次往里面插入一個數(shù),我們只需要比較插入的數(shù)和其父節(jié)點數(shù)的大小就行。
代碼:
k指的是插入的序號。建議大家這樣理解:
假設現(xiàn)在已經(jīng)構建好了有10個數(shù)的堆,我再往里面插入一個數(shù)為102,即第11個數(shù)。那么k=11.然后與其父節(jié)點(k/2=5),即arr[5]進行比較。若大于父節(jié)點就交換位置,并讓k/2=2,繼續(xù)進行下去,至到和根結點進行比較。
void shiftUp(int k,int arr[]){ while (k>1 && arr[k/2]<arr[k]) { swap(arr[k/2], arr[k]); k /=2; } }
取堆里面的數(shù):每次取都是取第一個位置的數(shù),也就是最大的數(shù)。
如題:現(xiàn)在構建好了一個堆,那么我取走第一個數(shù)后,整個堆就需要進行調整,那該如何?
目前思想:(以本遍博客上面的例子為例,讀者可以對照著看)
本題的:k代表開始的位置為1,j為子節(jié)點的位置(eg:指的是62這個根的左右兩個子節(jié)點)。
1.取走62,我就讓15代替62的位置。即,用最末尾的數(shù)字放到根節(jié)點上。
2.比較用15和62的兩個左右節(jié)點進行比較,如果大就不做處理,否則交換位置并且,讓k=j.
繼續(xù)走第二步
void shiftDown(int k,int arr[],int count ){
while (2*k< count) { //確認有左子節(jié)點
int j = 2*k;
if (j+1<count && arr[j+1] > arr[j]) { //如果有右節(jié)點
j+=1;
}
if (arr[k]>arr[j]) { 如果,比較發(fā)現(xiàn)字節(jié)點沒有父節(jié)點大,就退出
break;
}
swap(arr[k], arr[j]);//否則就交換位置
k = j;//然后讓k=j,繼續(xù)進行比較。
}
}
結尾:
堆排序算法還是很簡單的。
建立堆,然后一個一個的取出,那么這就是一個從大到小的一個有序的序列。
但行好事,莫問前程。
總結
以上是生活随笔為你收集整理的倍道而行 :堆(heap)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python的socket编程执行顺序_
- 下一篇: Netty源码之解码中两种数据积累器(C