Windows驅動開發學習記錄- x86 InlineHook位元組數計算(使用Hook Api lib 0.4 for C)
連結: 原文.
一,基礎知識(記憶)
重要
若樹的根節點記為 0
i處節點的left_child位置為:2 * i +1
i處節點的left_child位置為:2 * i +2
i處節點的parent位置為:( i - 1 )/ 2
大根堆 ,小根堆
1,為完全二叉樹
:新增新節點的順序是:從上到下,從左到右
2,滿足:父節點 > 子節點(小根堆相反)
3,可以用一個一維陣列表示
二,heapify:堆調整
1,針對結點 i,將其兩個子節點找出來,(越界的忽略)
2,找到這個最小單位的完全二叉樹 的最大值,並將其交換至父節點的位置
3,遞迴呼叫,以便維護:交換後子節點與其子結點被破壞的堆關係,
4.遞迴出口:葉節點
5,結果:構造一個最小單位的
完全二叉樹對應的堆
// 交換結點位置 void swap(int a[], int i, int j) { int t = a[i]; a[i] = a[j]; a[j] = t; } // 堆調整 void heapify(int tree[], int n, int i) { if (i >= n) return; int c1 = 2 * i + 1; int c2 = 2 * i + 2; int max = i; if (c1 < n&&tree[c1] > tree[max]) max = c1; if (c2 < n&&tree[c2] > tree[max]) max = c2; if (max != i) { swap(tree, max, i); // 將最大值移至父節點 heapify(tree, n, max); // 遞迴維護下面的結點 } }
二,build_heap:構造堆
由於 heapify 會遞迴呼叫維護下面的堆,所以想要構造完整的堆,
需要從下面往上構造
:先找到最後一個父結點,再從最後一個父結點開始向上呼叫 heapify
// 構造堆 void build_heap(int tree[], int n) { int last_node = n - 1; int parent = (last_node - 1) / 2; // 最後一個父結點 int i; for ( i = parent; i >= 0; i--) // 從最後一個父結點開始向上呼叫 heapify heapify(tree, n, i); }
三,heap_sort:利用堆進行堆排序
由堆可以得到什麼呢 ?首先根結點是最大的,第二層的兩個節點是 第二大和第三大的。
於是,利用這點就可以排序了
1,可以想到:既然根結點已經是最大的,那麼就把這個數提走,剩下的再構造一個新堆。然後再提走根結點,再構造新的堆,迴圈往復。
2,但是這樣就會面臨一個問題?拿走根結點之後,根結點的數值由誰取代?
3,由於該結點要滿足:移動該節點到根結點後,要對堆的結構破壞儘可能小,而且堆的大小還要因為結點少了一個進行減1(即 陣列表示堆的範圍要減 一)。顯然最後一個結點是最好的選擇了。移動後既不會影響到後面的結點,原來的位置還因為空了可以直接取消掉。
4,關鍵的 一步出現了。我們用最後一個結點替換根結點,此時根結點和第二層的兩個結點構成一個最小單位的最小二叉樹,此時就可以直接呼叫 heapify函式 ,形成一個新的堆。沒有必要用 build_heap函式,因為此時最大值就在第二層,根結點會因為遞迴維護被替換到最後一層,其他結點也會因為遞迴維護而得到調整。
5,至於拿出來的結點放哪,當然還是放在原來的數組裡咯。
由於陣列前面存的是堆,於是可以從最後面的位置依次往前放,還可以形成升序序列。
用大根堆,因為我們想要的是升序序列,
如果想要降序序列的話,也可以用小根堆。
// 利用堆進行堆排序
//從小到大排序
void heap_sort(int tree[], int n)
{
build_heap(tree, n);
int i;
for (i = n - 1; i >= 0; i--)
// 每次取出根結點後,堆減少一個節點
{
swap(tree, i, 0);
//交換根節點和最後一個節點
heapify(tree, i, 0);
// (假砍斷)對從0到i的元素構造一個新堆,(i是指新堆節點數)
}
}
主函式
int main(void)
{
int i;
int n;
int m;
scanf("%d %d",&n,&m);
int tree[n+1] ;
for(i=0; i<n; i++)
{
scanf("%d",&tree[i]);
}
// build_heap(tree, n);
// heapify(tree,n,0); // 堆調整
heap_sort(tree, n);
for ( i = n-1; i >=n-m+1; i--)
{
printf("%d ", tree[i]);
}
printf("%d\n", tree[i]);
return 0;
}