0
点赞
收藏
分享

微信扫一扫

heap & heap sort & priority queue: data structure

boomwu 2021-09-30 阅读 58
与 下面一篇 可 互为 参考

https://www.jianshu.com/p/2044704768c9

`1. heap data structure 应用`

(1) heap sort 中 管理 information: 最大堆

(2) 构造 priority queue: 最小堆

`2. heap sort`

(1) 与 归并排序 区别

T(n) = O(n lgn)

(2) 与 插入排序 区别 
任何时候 只需 `常数个 额外元素空间` 存储 `临时 data`

1 heap

(二叉) 堆 是 1 个数组, 可 视为 完全二叉树

`除 最底层外, 树 completely filled` /
`每层 从左向右 fill`
1. 表示 heap 的 array A 有 2 个属性: 

(1) A.length: array element num
(2) A.heap_size: array 中 valid heap element num

0 <= A.length <= A.heap_size

A[1.. A.length] 存 array elem
A[1..A.heap_size] 存 heap elem

root: A[1]
2. node index i => parent / lchild / rchild index
(1) i = 1..A.length

parent(i)
  return floor( i / 2 ) = i / 2

l_child(i)
  return 2*i

r_child(i)
  return 2*i + 1
  
(2) i = 0..A.length - 1
parent(i)
  return floor( (i+1)/ 2 - 1 ) = (i+1)/ 2 - 1

l_child(i)
  return 2*(i+1) - 1 = 2*i + 1

r_child(i)
  return 2*(i+1) + 1 - 1 = 2*i + 2

3. 最 大/小 堆: heap sort / 构造 priority queue

parent.key >=/<= child.key

A[parent(i)] >= A[i]

A[parent(i)] <= A[i]

4. heap node 高度 & heap 基本操纵 T(n)

(1) heap node 高度:
node 到 leaf node 最长 simple path 上 边数

如: 上图中
堆 的 高度 = 2 = 3 - 1

(2) heap 基本操纵 T(n)

2 维护堆 性质

以 最大堆 为例

max_heapify:

input:
array A, index i = 1..A.length

调 max_heapify 时, 假定 
以 lchild(i) / rchild(i) 为 root 的 子树 是 max_heap

max_heapify 思路:

让 A[i] 在 max_heap 中 逐级下降

. 使 以 下标 i 为 root_index 的 子树 重新遵循 max_heap 性质
// O(lgn)
// i = 1..A.length
max_heapify(A, i)
    lchild = l_child(i)
    rchild = r_child(i)
    
    //(1) cmp i/lchild/rchild 3 node.key, 
    //    最大者 index 记为 largest_index
    // else:
    // case1: lchild > A.heap_size
    // case2: lchild <= A.heap_size && A[lchild] <= A[i]
    if lchild <= A.heap_size && A[lchild] > A[i]
        largest_index = lchild
    else 
        largest_index = i
    
    if rchild <= A.heap_size && A[rchild] > A[largest_index]
        largest_index = rchild
    
    //(2) 若 largest_index != i, 
    //    交换 i/largest_index node.key 
    //  + 对 largest_index node 递归 调 max_heapify
    if largest_index != i
        exchange A[i] with A[largest_index]
        max_heapify(A, largest_index)
exchange(A[i], A[j]) // swap

3 建堆

自底向上 调 max_heapify 把 n=A.length 的 array A[1..A.length] 转换为 max_heap

子数组 A[ n/2 + 1 .. n] 中 elem 都是 leaf node
leaf node 可视为 只含 1 个 elem 的 heap

index = 0 开始:
A[ n/2 .. n-1] 中 elem 都是 leaf node
// O(n)
build_max_heap(A)
    A.heap_size = A.length
    
    for i = A.length/2 downto 1
        max_heapify(A, i)

4 heap sort

思路:
(1) 先 调 build_max_heap 把 A[1..n = A.length] 建成 max_heap

(2) `max_elem 总在 根节点 A[1]`
1) `交换 A[1] 与 A[n]  <=> max_elem 放 A[n]`
2) `heap 中 去掉 node n: --n 即可`
3) 剩余 node 中, 原 root 的 lchild/rchild 仍为 max_heap
   root_new 可能 违背 max_heap 性质
   => 
   调 `max_heapify(A, 1) 在 A[1.. n-1] 上 维护 max_heap`
    
`循环 (2) 过程: heap_size 从 n 将到 2`
    `每次 循环 前/后 heap size n->2 / n-1 -> 1`
// (n-1) * O(lgn) = O(n*lgn)
heap_sort(A)
    build_max_heap(A)
    
    for i = A.length downto 2
        exchange A[i] with A[1]
        --A.heap_size
        max_heapify(A, 1)

5 priority queue

heap sort 较优秀, 但 实际应用中 qiuck sort 性能通常更好

heap 的 另一应用:

1. priority queue

是 1 种 data structure, 
用于 维护 一组 element 的 集合 S (set), 
`每个 element 有 1个 key, 表示 优先级`
1.1 max priority queue 

(1) 操作

1) insert(S, x) // 插入

2) maximum(S) // return max key elem 
   <=> top() if stack

3) extract_max(S) // remove and return max key elem 
   <=> pop() 

4) increase_key(S, x, key) 
   increase elem x 的 x.key to key(假定 >= x.key)
   `insert 的 辅助函数`

(2) 应用: OS task schedule

1) max priority queue record `将要执行` 的 
`各 tasks 及其 相对 优先级`

2) 某 task 完成/中断 后, scheduler 调 extract_max 
从 所有 waiting tasks 中 选出 优先级最高 的 task 来 执行

3) 任何时候, scheduler 可 调 insert 加入 a task 到 queue
1.2 min priority queue 

(1) 操作

1) insert(S, x)

2) minimum(S)

3) extract_min(S)

4) decrease_key(S, x, key) 

(2) 应用: 事件驱动 模拟器

1.3 priority queue elem 也要存 对应 obj 的 handle: pointer / index

通常, 要确定 
`which obj 对应 a given priority queue elem`, 
反之亦然

=> 
(1) 用 heap 实现 priority queue 时, 
要在 每个 heap elem 中
store `corresponding obj 的 handle(句柄)`:
`pointer to obj / index of obj(elem of obj array)`

handle 含义 取决于 具体 application

(2) 同样, application obj 中
`store heap 中 对应 elem 的 handle`
`( 通常 是 index of heap array)`

(3) `heap operations 中`, 
`elem 会 改变其 在 heap array 中 position`
=> 
重新确定 heap elem position 时, 
也要 `update 相应 application obj 中 的 handle`

2. insert(S, x)

insert(A, key)
    ++A.heap_size
    A[A.heap_size] = -infinity
    increase_key(A, A.heap_size, key)

3. increase_key(S, x, key)

increase_key(A, index, key)
    if key < A[index]
        error: "new key is smaller than current key"
    
    A[index] = key
    while index > 1 && A[parent(index)] < A[index]
        exchange A[parent(index)] with A[index]
        inedx = parent(i)

6. maximum(S)

maxmium(A)
    return A[1]

5. extract_max(S)

extract_max(A)
    if A.heap_size < 1
        error: heap underflow
    
    // 1) record max= root_elem
    max = A[1]
    
    // 2) A[1] 替换为 A[n]
    A[1] = A[A.heap_size]
    
    // 3) remove A[n] <=> remove old_root_elem
    --A.heap_size
    
    // 4) 对 root 维护 max_heap 性质
    max_heapify(A, 1)
    
    // 5) return old_root_elem
    return max

6 implement

// 1.
// b_tree_client.cpp : Defines the entry point for the console application.
// binary order tree
#include <cstdio>
#include <climits> // INT_MIN
#include "heap.h"

#define N 5

// heap_array index / value == elem.key, 
// omit elem.handle

// 前 4 个 作 heap_elem, 第 5个 invalid, 待 max_heap insert
int heap_array[N] = {10, 20, 5, 30, 0}; 
int heap_size = 0;

// -----1. 
int 
parent(int i)
{
    return (i+1)/ 2 - 1;
}

int
l_child(int i)
{
    return 2*i + 1;
}

int
r_child(int i)
{
    return 2*i + 2;
}
  

//-----2. max_heapify / build_max_heap / heap_sort

void swap(int* v1, int* v2)
{
    int tmp = *v1;
    *v1 = *v2;
    *v2 = tmp;
}

//---(1) maintain heap property
// O(lgn)
// i = 0..heap_size-1
void
max_heapify(int* p_heap_arr, unsigned int i)
{
    int lchild = l_child(i);
    int rchild = r_child(i);
    int largest_index = 0;

    //(1) cmp i/lchild/rchild 3 node.key, 
    //    最大者 index 记为 largest_index
    if( lchild < heap_size && p_heap_arr[lchild] > p_heap_arr[i])
        largest_index = lchild;
    else 
        largest_index = i;
    
    if(rchild < heap_size && p_heap_arr[rchild] > p_heap_arr[largest_index])
        largest_index = rchild;
    
    //(2)
    if(largest_index != i)
    {
        swap(p_heap_arr + i, p_heap_arr + largest_index);
        max_heapify(p_heap_arr, largest_index);
    }
}

// --- (2) build heap
// O(n)
void
build_max_heap(int* p_heap_arr)
{
    heap_size = N -1; // 留 1个 插入 / 删除 position
    
    for(int i = heap_size/2 - 1; i >= 0; --i)
        max_heapify(p_heap_arr, i);
}
    
// --- (3) heap sort    
void
heap_sort(int* p_heap_arr)
{
    build_max_heap(p_heap_arr);
    
    for( int i = heap_size - 1;  i >= 1; --i)
    {
        swap(p_heap_arr + i, p_heap_arr);
        --heap_size;
        max_heapify(p_heap_arr, 0);
    }
}
        

//-----3 
void
increase_key(int* p_heap_arr, unsigned int index, int key)
{
    if( key < p_heap_arr[index])
    {
        printf("new key is smaller than current key");
    }
    
    p_heap_arr[index] = key;
    
    while( index > 0 && p_heap_arr[ parent(index) ] < p_heap_arr[index] )
    {
        swap( p_heap_arr + parent(index), p_heap_arr + index); 
        index = parent(index);
    }
}

// --- (4) insert
void
insert(int* p_heap_arr, int key)
{
    ++heap_size;
    
    p_heap_arr[heap_size - 1] = INT_MIN;
    
    increase_key(p_heap_arr, heap_size - 1, key);
}

int
maxmium(int* p_heap_arr)
{
    return p_heap_arr[0];
}

// --- (5) extract
int
extract_max(int* p_heap_arr)
{
    if(heap_size < 0)
        printf("heap underflow");
    
    // 1) record max= root_elem
    int max = p_heap_arr[0];
    
    // 2) A[1] 替换为 A[n]
    p_heap_arr[0] = p_heap_arr[heap_size - 1];
    
    // 3) remove A[n] <=> remove old_root_elem
    --heap_size;
    
    // 4) 对 root 维护 max_heap 性质
    max_heapify(p_heap_arr, 0);
    
    // 5) return old_root_elem
    return max;
}

void 
print_heap(int* p_heap_arr)
{
    printf("---heap: \n");
    
    for(int i = 0; i < heap_size; ++i)
        printf("%d ", *(p_heap_arr + i) );
    
    printf("\n");
}

void
print_heap_sort_result(int* p_heap_arr, int heap_size_old)
{
    printf("---heap_sort_result: \n");

    for (int i = 0; i < heap_size_old; ++i)
        printf("%d ", *(p_heap_arr + i));

    printf("\n");
}
//2.
// b_tree_client.cpp : Defines the entry point for the console application.
// binary order tree
#include <cstdio>
//#include <iostream>
//#include <vector>
//#include <stack>
#include <climits> // INT_MIN
#include "heap.h"

#define N 5

// heap_array index / value == elem.key, 
// omit elem.handle

// 前 4 个 作 heap_elem, 第 5个 invalid, 待 max_heap insert
int heap_array[N] = {10, 20, 5, 30, 0}; 
int heap_size = 0;

// -----1. 
int 
parent(int i)
{
    return (i+1)/ 2 - 1;
}

int
l_child(int i)
{
    return 2*i + 1;
}

int
r_child(int i)
{
    return 2*i + 2;
}
  

//-----2. max_heapify / build_max_heap / heap_sort

void swap(int* v1, int* v2)
{
    int tmp = *v1;
    *v1 = *v2;
    *v2 = tmp;
}

//---(1) maintain heap property
// O(lgn)
// i = 0..heap_size-1
void
max_heapify(int* p_heap_arr, unsigned int i)
{
    int lchild = l_child(i);
    int rchild = r_child(i);
    int largest_index = 0;

    //(1) cmp i/lchild/rchild 3 node.key, 
    //    最大者 index 记为 largest_index
    if( lchild < heap_size && p_heap_arr[lchild] > p_heap_arr[i])
        largest_index = lchild;
    else 
        largest_index = i;
    
    if(rchild < heap_size && p_heap_arr[rchild] > p_heap_arr[largest_index])
        largest_index = rchild;
    
    //(2)
    if(largest_index != i)
    {
        swap(p_heap_arr + i, p_heap_arr + largest_index);
        max_heapify(p_heap_arr, largest_index);
    }
}

// --- (2) build heap
// O(n)
void
build_max_heap(int* p_heap_arr)
{
    heap_size = N -1; // 留 1个 插入 / 删除 position
    
    for(int i = heap_size/2 - 1; i >= 0; --i)
        max_heapify(p_heap_arr, i);
}
    
// --- (3) heap sort    
void
heap_sort(int* p_heap_arr)
{
    build_max_heap(p_heap_arr);
    
    for( int i = heap_size - 1;  i >= 1; --i)
    {
        swap(p_heap_arr + i, p_heap_arr);
        --heap_size;
        max_heapify(p_heap_arr, 0);
    }
}
        

//-----3 
void
increase_key(int* p_heap_arr, unsigned int index, int key)
{
    if( key < p_heap_arr[index])
    {
        printf("new key is smaller than current key");
    }
    
    p_heap_arr[index] = key;
    
    while( index > 0 && p_heap_arr[ parent(index) ] < p_heap_arr[index] )
    {
        swap( p_heap_arr + parent(index), p_heap_arr + index); 
        index = parent(index);
    }
}

// --- (4) insert
void
insert(int* p_heap_arr, int key)
{
    ++heap_size;
    
    p_heap_arr[heap_size - 1] = INT_MIN;
    
    increase_key(p_heap_arr, heap_size - 1, key);
}

int
maxmium(int* p_heap_arr)
{
    return p_heap_arr[0];
}

// --- (5) extract
int
extract_max(int* p_heap_arr)
{
    if(heap_size < 0)
        printf("heap underflow");
    
    // 1) record max= root_elem
    int max = p_heap_arr[0];
    
    // 2) A[1] 替换为 A[n]
    p_heap_arr[0] = p_heap_arr[heap_size - 1];
    
    // 3) remove A[n] <=> remove old_root_elem
    --heap_size;
    
    // 4) 对 root 维护 max_heap 性质
    max_heapify(p_heap_arr, 0);
    
    // 5) return old_root_elem
    return max;
}

void 
print_heap(int* p_heap_arr)
{
    printf("---heap: \n");
    
    for(int i = 0; i < heap_size; ++i)
        printf("%d ", *(p_heap_arr + i) );
    
    printf("\n");
}

void
print_heap_sort_result(int* p_heap_arr, int heap_size_old)
{
    printf("---heap_sort_result: \n");

    for (int i = 0; i < heap_size_old; ++i)
        printf("%d ", *(p_heap_arr + i));

    printf("\n");
}
//3.
#include <cstdio>
#include <stdlib.h>    // malloc / free
#include "heap.h"

// === test cases: ===
void 
Test(int* p_heap_arr, int key)
{
    // (1)
    build_max_heap(p_heap_arr);;
    print_heap(p_heap_arr);
    
    // (2)
    insert(p_heap_arr, key);
    print_heap(p_heap_arr);
    
    // (3)
    int max = extract_max(p_heap_arr);
    printf("--- max: %d\n", max);
    print_heap(p_heap_arr);
    
    // (4)
    int heap_size_old = heap_size;
    heap_sort(p_heap_arr);
    print_heap_sort_result(p_heap_arr, heap_size_old);
}

void Test1()
{  
    int key = 15;
    
    Test(heap_array, key);
}

int main()
{
    Test1();
    return 0;
}
举报

相关推荐

0 条评论