heap & max priority queue

开发者 2024-9-9 12:40:20 8 0 来自 中国
heap & max priority queue

section1: heap

0 概述

1 (二叉) 堆 是1个 数组, 可视为 完全二叉树 root: A[0]
    `除 最底层 外`, 树 `完全填满: 每层 从左向右 fill`2 heap 数组 A 2个属性
(1) A.length: 数组元素数
(2) A.heapSize: 有用堆元素数
3 nodeIndex i = 0..A.length - 1 => parentIndex / lcIndex / rcIndex index
    parentIndex(i)      return floor( (i+1)/ 2 - 1 )  = (i+1)/ 2 - 1    lcIndex(i)      return 2*(i+1) - 1            = 2*i + 1    rcIndex(i)      return 2*(i+1) + 1 - 1        = 2*i + 24 应用
(1) heap sort 中 管理 information: 最大堆 A[parentIndex(i)] >= A
(2) 构造 priority queue: 最小堆 A[parentIndex(i)] <= A
(3) heap sort
    1) 与 归并排序 区别        T(n) = O(n lgn)    2) 与 插入排序 区别                     任何时间 只需 `常数个 额外元素空间` 存储 `暂时 data`(4) heap node 高度: node 到 leaf node 最长 simple path 上 边数
以下以 最大堆 为例

1  维护堆性子: maxHeapify(A, curIndex)

假定 curIndex 以上满足 最大堆性子
自 curIndex 向下 让 A[curIndex] 在 maxHeap 中 逐级下降, 使 curIndex 子树 重新遵照 maxHeap 性子
    code [1] 求 本 curIndex.key+lc+rc 中的 maxIndex: curIndex/lcIndex/rcIndex
[2] 若 本 curIndex.key 违背 最大堆性子 => 用 maxIndex.key & maxIndex 互换 & 递归
maxHeapify(A, curIndex) // O(lgn)    lcIndex = lcIndex(curIndex)    rcIndex = rcIndex(curIndex)        // (1) 求 本 curIndex.node+lc+rc 中的 maxIndex: curIndex/lcIndex/rcIndex     maxIndex = curIndex        if lcIndex <= A.heapSize && A[lcIndex] > A[curIndex]        maxIndex = lcIndex    if rcIndex <= A.heapSize && A[rcIndex] > A[maxIndex]        maxIndex = rcIndex        // (2) 若 本 curIndex.node 违背 最大堆性子 => 用 maxIndex.key & maxIndex 互换 & 递归    if maxIndex != curIndex        swap(A[curIndex], A[maxIndex])        maxHeapify(A, maxIndex)2  建堆 buildMaxHeap(A)

对 A[0 .. A.length - 1 ] 自底向上(index 减小) 调 maxHeapify
A[ n/2 .. n-1 ] 均为 叶结点: 视为 只含 1 个 elem 的 heap
=> 只需对 非叶结点 A[n/2 - 1 .. 0] 自底向上(index 减小) 调 maxHeapify
    ————————————————————————————————————————————————————    n = A.length    叶 index: 归纳法    完全二叉数布局    ————————————————————————————————————————————————————                                                0        3           1 / 2                   1       2    ————————————————————————————————————————————————————        4           2 / 3                       0                                            1       2                                        3     ————————————————————————————————————————————————————        ...         = n/2 .. n-1                    ————————————————————————————————————————————————————buildMaxHeap(A) // O(n)     A.heapSize = A.length    for(int i = heapSize/2 - 1; i >= 0; --i)        maxHeapify(A, i)3  heap sort: heapSort(A)

heap sort 较良好, 但 现实应用中 qiuck sort 性能通常更好
(1) 建堆 => 顶 最大
(2) heapSize - 1 次 循环
[1] 互换 顶 与 底
[2] 新底 index&index.key 均最大 => 下一趟排序去掉它: --heapSize;
[3] 新顶 (index = 0) index.key notMax => 粉碎 最大堆性子 => 对 新顶 index 调 maxHeapify(A, 0)
heapSort(A) // (n-1) * O(lgn) = O(n*lgn)    buildMaxHeap(A)         for( int i = heapSize - 1;  i >= 1; --i)        swap(A, A[0])        --A.heapSize      // update heapSize        maxHeapify(A, 0)section2: max priority queue: key 体现 优先级

1  insert(A, key)

1] heapSize 自增     2] 底 初始化为 最小负值: 辅助函数中 置为 key    3] increase 底.key 到 key insert(A, key)    ++A.heapSize    A[A.heapSize] = 负最大值    increaseKey(A, A.heapSize, key)increaseKey(A, index, key): insert 辅助函数

1) index.key 置 key => 违背 最大堆性子
2) 从 底 开始, 逐层 swap/上升(index 减小) 到 不再与 A[parentIndex] 逆序 的 位置
increaseKey(A, index, key)    if key < A[index]        error: "printf("new key 小于 curIndex key");"        A[index] = key    while(index > 1 && A[index] > A[parentIndex(index)] )        swap(A[index], A[ parentIndex(index )] )        inedx = parentIndex(index)2 extractMax(S) <-> stack 的 topAndPop()

为 使 heap 总是 从 index = 0 开始, 将 底 node(index = heapSize - 1) 挪到 顶(index = 0) & update heapSize
=> 违背 最大堆性子 -> 对 顶(index = 0) 调 maxHeapify(A, 0) 重新维护 最大堆性子
extractMax(A)    if A.heapSize < 1        error: heap underflow        max = A[0]                  // 1] - - - - - - - - -                                 //                      |       A[0] = A[A.heapSize - 1]    // 3]                   |    --A.heapSize                // 4] update heapSize   |    maxHeapify(A, 0)            // 5]                   |                                //                      |    return max                  // 2] - - - - - - - - -         3 maxElem(S) <-> stack 的 top()

应用: OS 任务调理

(1) max priority queue 记载 各 tasks 的 优先级
(2) 某 task 完成/停止 后, scheduler 调 extractMax, 从 waiting tasks 中 选出 优先级最高 的 task 去实行
(3) 任何时间, scheduler 可调 insert, 参加 task 到 queue
section3: min priority queue

应用: 变乱驱动 模拟器

section4: priority queue 也要存 对应 obj 的 handle: ptr / index

// heap.h#ifndef _HEAP_H#define _HEAP_H#define N 5extern int heap_array[N]; extern int heapSize;int parentIndex(int i);int lcIndex(int i);int rcIndex(int i);void maxHeapify(int* parentIndex, unsigned int curIndex);void buildMaxHeap(int* p_heap_arr);void heapSort(int* p_heap_arr);void insert(int* p_heap_arr, int key);int extractMax(int* p_heap_arr);int maxElem(int* parentIndex);void printHeap(int* p_heap_arr);#endif// 二叉排序树#include <cstdio>#include <climits> // INT_MIN#include "heap.h"#define N 5void swap(int* v1, int* v2){    int tmp = *v1;    *v1 = *v2;    *v2 = tmp;}// Note: 末了1个数组元素 invalid, 待 插int heap[N] = {10, 20, 5, 30, 0}; int heapSize = 0;// === 3 个 index int parentIndex(int i) { return (i+1)/ 2 - 1; }int lcIndex(int i) { return 2*i + 1; }int rcIndex(int i) { return 2*i + 2; }// === 3 大函数: maxHeapify / buildMaxHeap / heapSortvoid maxHeapify(int* parentIndex, unsigned int curIndex){       // [1]    int lcIndex = lcIndex(curIndex);    int rcIndex = rcIndex(curIndex);        // [2]    int maxIndex = 0;    if( lcIndex < heapSize && parentIndex[lcIndex] > parentIndex)        maxIndex = lcIndex;    else         maxIndex = curIndex;    if(rcIndex < heapSize && parentIndex[rcIndex] > parentIndex[maxIndex])        maxIndex = rcIndex;        // [3]    if(maxIndex != curIndex)    {        swap(parentIndex + curIndex, parentIndex + maxIndex);        maxHeapify(parentIndex, maxIndex);    }}void buildMaxHeap(int* parentIndex){    heapSize = N -1;    // Note: 留 1个 插入 / 删除 position        for(int i = heapSize/2 - 1; i >= 0; --i)        maxHeapify(parentIndex, i);}    void heapSort(int* parentIndex){    buildMaxHeap(parentIndex);        for( int i = heapSize - 1;  i >= 1; --i)    {        swap(parentIndex + i, parentIndex);        --heapSize;        maxHeapify(parentIndex, 0);    }}        // === insert & 辅助 increaseKey + extractMaxvoid increaseKey(int* parentIndex, unsigned int index, int key){    if( key < parentIndex[index])         printf("new key 小于 curIndex key");         parentIndex[index] = key;        while( index > 0 && parentIndex[ parentIndex(index) ] < parentIndex[index] )    {        swap( parentIndex + parentIndex(index), parentIndex + index);         index = parentIndex(index);    }}void insert(int* parentIndex, int key){    ++heapSize;    parentIndex[heapSize - 1] = INT_MIN;    increaseKey(parentIndex, heapSize - 1, key);}int maxElem(int* parentIndex){ return parentIndex[0]; }int extractMax(int* parentIndex){    if(heapSize < 0)        printf("heap underflow");    int max = parentIndex[0];        parentIndex[0] = parentIndex[heapSize - 1];    --heapSize;    maxHeapify(parentIndex, 0);        return max;}void printHeap(int* parentIndex){    printf("---heap: \n");        for(int i = 0; i < heapSize; ++i)        printf("%d ", *(parentIndex + i) );        printf("\n");}// === client #include <cstdio>#include <stdlib.h>    // malloc / free#include "heap.h"// === test cases: ===void Test(int* parentIndex, int key){    buildMaxHeap(parentIndex);          // 1)    printHeap(parentIndex);        insert(parentIndex, key);               // 2)    printHeap(parentIndex);        int max = extractMax(parentIndex);  // 3)    printf("--- max: %d\n", max);    printHeap(parentIndex);    heapSort(parentIndex);              // 4)       }void Test1(){      int key = 15;        Test(heap, key);}int main(){    Test1();    return 0;} 2.png
您需要登录后才可以回帖 登录 | 立即注册

Powered by CangBaoKu v1.0 小黑屋藏宝库It社区( 冀ICP备14008649号 )

GMT+8, 2024-10-19 04:20, Processed in 0.183757 second(s), 35 queries.© 2003-2025 cbk Team.

快速回复 返回顶部 返回列表