与 下面一篇 可 互为 参考
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;
}