【算法與數據結構】二叉堆和堆排序

構建二叉堆

二叉堆自己也是個二叉樹,有兩個限制:web

  • 堆必須是徹底二叉樹
  • 堆中任一父結點的值大於其左右兩子節點的值(大頂堆),或小於其左右兩子節點的值(小頂堆)

由於徹底二叉樹中,數據排列順序是從上而下,從左至右,因此能夠用數組的形式保存數據。一般根結點做爲數組的 0 號元素,其左右孩子分別是 2 號、3 號元素,以此類推。api

保證一個元素符合要求

保證一個元素符合要求的過程,能夠叫作 heapify。其順序是:數組

  1. 若是元素超限,退出
  2. 比較元素值及其左右孩子結點的值(前提是有),若是元素值是最大的則無需交換,不然跟最大值交換
  3. 回到第一步,遞歸比較元素的左右兩個孩子
void swap(int tree[], int i, int j) {
    int tmp = tree[i];
    tree[i] = tree[j];
    tree[j] = tmp;
}
void heapify(int tree[], int n, int i) {
    if (i >= n) {
        return;
    }
    int max = i;
    int c1 = i * 2 + 1;
    int c2 = i * 2 + 2;
    if (c1 < n && tree[i] < tree[c1]) {
        max = c1;
    }
    if (c2 < n && tree[max] < tree[c2]) {
        max = c2;
    }
    if (max != i) {
        swap(tree, i, max);
    }
    heapify(tree, n, c1);
    heapify(tree, n, c2);
}

保證整個二叉樹符合要求

每次 heapify 能夠確保二叉樹中的最大元素上移一層,因此須要對除最後一層外的全部元素逐個調用 heapify:svg

void heapifyAll(int tree[], int n) {
    int last = (n - 1) / 2;
    int i;
    for (i = last; i >= 0; i--) {
        heapify(tree, n, i);
    }
}

排序

二叉堆構建完成後,就能夠對其進行排序了。步驟以下:spa

  1. 交換根結點和最後一個結點
  2. 結點個數減一,而後從新對根結點進行 heapify
  3. 繼續第1、二步,直到沒有結點爲止
void heapSort(int tree[], int n) {
    heapifyAll(tree, n);
    int i;
    for (i = n - 1; i >= 0; i--) {
        swap(tree, 0, i);
        heapify(tree, i, 0);
    }
}

完整代碼:

#include <stdio.h>

void swap(int tree[], int i, int j) {
    int tmp = tree[i];
    tree[i] = tree[j];
    tree[j] = tmp;
}
// 對單個結點堆化
void heapify(int tree[], int n, int i) {
    if (i >= n) {
        return;
    }
    int max = i;
    int c1 = i * 2 + 1;
    int c2 = i * 2 + 2;
    if (c1 < n && tree[i] < tree[c1]) {
        max = c1;
    }
    if (c2 < n && tree[max] < tree[c2]) {
        max = c2;
    }
    if (max != i) {
        swap(tree, i, max);
    }
    heapify(tree, n, c1);
    heapify(tree, n, c2);
}

// 對整個徹底二叉樹堆化
void heapifyAll(int tree[], int n) {
    int last = (n - 1) / 2;
    int i;
    for (i = last; i >= 0; i--) {
        heapify(tree, n, i);
    }
}

// 堆排序
void heapSort(int tree[], int n) {
    heapifyAll(tree, n);
    int i;
    for (i = n - 1; i >= 0; i--) {
        swap(tree, 0, i);
        heapify(tree, i, 0);
    }
}
int main(void) {
    int i;
    int tree[6] = {3, 2, 5, 4, 7, 1};
    // heapify(tree, 6, 1);
    heapifyAll(tree, 6);


    printf("堆:\n");
    for( i = 0; i < 6; i++) {
        printf("%d\n", tree[i]);
    }
    heapSort(tree, 6);

    printf("新順序:\n");
    for( i = 0; i < 6; i++) {
        printf("%d\n", tree[i]);
    }
    return 0;
}
相關文章
相關標籤/搜索