1. 程式人生 > 其它 >Windows驅動開發學習記錄- x86 InlineHook位元組數計算(使用Hook Api lib 0.4 for C)

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;
}