文章目录
堆
定义
- 逻辑结构:完全二叉树
- 物理(存储)结构:顺序表
- 大根堆
- 每一个节点元素的值都不小于左右子树的值
- 根节点的元素最大
- 小根堆
- 每一个节点元素的值都不大于左右子树的值
- 根节点的元素最小
下标从0开始时:
- 对于完全二叉树,最后一个分支是第n/2个节点 下标为n/2-1
- 对于完全二叉树,第i个节点如果右左右孩子,则左孩子第2i个,右孩子是第2i+1个
- 对于完全二叉树,下标为i的的节点如果右左右孩子,则左孩子下标为2i+1,右孩子下标为2i+2
- 对于完全二叉树,第2i个节点父节点为第i/2个
- 对于完全二叉树,下标为i节点的父节下标为(i - 1)/2
大根堆实现
结构体定义
#define SUCCESS 0
#define FAILURE -1
typedef int ElemType;
struct MaxHeap {
size_t cap; // 容量
size_t size; // 元素个数
ElemType elems[];
};
typedef struct MaxHeap* MHeap;
静态函数列表
用于维护堆
// 元素向下沉
static void pushdown_maxheap(ElemType elems[], size_t pos, size_t n);
// 元素向上浮
static void pushup_maxheap(ElemType elems[], size_t pos);
基本功能声明
// 创建一个空的大根堆
MHeap create_maxheap(size_t cap);
// 创建大根堆时的调整
void rebuild_maxheap(ElemType elems[], size_t n);
// 用n个元素创建大根堆
MHeap create_by_elems_maxheap(ElemType elems[], size_t n);
// 压入一个元素之后需要保持大根堆的特性
int push_maxheap(MHeap heap, ElemType elem);
// 弹出堆顶
int pop_front_maxheap(MHeap heap, ElemType *pElem);
// 删除指定位置元素
int remove_maxheap(MHeap heap, size_t pos, ElemType *pElem);
// 删除最后一个元素
int pop_back_maxheap(MHeap heap, ElemType *pElem);
静态函数实现
用于维护堆
元素向下沉(向下维护堆) pushdown_maxheap
static void pushdown_maxheap(ElemType elems[], size_t pos, size_t n)
{
ElemType key = elems[pos];
size_t child = 2 * pos + 1;
while (child < n) { // 左孩子存在
if (child + 1 < n && elems[child] < elems[child + 1]) { // 右孩子存在,并且比左孩子大
++child;
}
// 记录较大孩子的下标
if (key < elems[child]) { // 孩子节点比父节点大
elems[pos] = elems[child]; // 把孩子节点元素放入父节点中
pos = child; // 向下走
child = 2 * pos + 1;
} else {
break;
}
}
elems[pos] = key; // key的最终位置
}
元素向上浮(向上维护堆) pushup_maxheap
static void pushup_maxheap(ElemType elems[], size_t pos)
{
ElemType key = elems[pos]; // 要pushup的元素
while (pos > 0) {
int parent = (pos - 1) / 2; // 父节点
if (elems[parent] < key) { // 比父节点大
elems[pos] = elems[parent]; // 父节点向下走
pos = parent; // elem向上走
} else {
break;
}
}
elems[pos] = key; // key的最终位置
}
基本功能实现
创建一个空的大根堆 create_maxheap
MHeap create_maxheap(size_t cap)
{
MHeap heap = (MHeap)malloc(sizeof(struct MaxHeap) + cap * sizeof(ElemType));
if (heap != NULL) {
heap->cap = cap;
heap->size = 0;
}
return heap;
}
建大根堆时的调整 rebuild_maxheap
从最后一个非叶子节点开始
void rebuild_maxheap(ElemType elems[], size_t n)
{
for (int i = n / 2 - 1; i >= 0; --i) {
pushdown_maxheap(elems, i, n);
}
}
用n个元素创建大根堆 create_by_elems_maxheap
MHeap create_by_elems_maxheap(ElemType elems[], size_t n)
{
MHeap heap = (MHeap)malloc(sizeof(struct MaxHeap) + n * sizeof(ElemType));
if (heap != NULL) {
heap->cap = n;
heap->size = n;
for (int i = 0; i < n; ++i) {
heap->elems[i] = elems[i];
}
rebuild_maxheap(heap->elems, heap->size); // 建堆 调整到满足堆的特性
}
return heap;
}
压入一个元素 push_maxheap
int push_maxheap(MHeap heap, ElemType elem)
{
assert(heap != NULL);
if (heap->cap == heap->size) {
return FAILURE;
}
heap->elems[heap->size] = elem; // 加入末尾
pushup_maxheap(heap->elems, heap->size); // 向上维护堆
++heap->size;
return SUCCESS;
}
弹出堆顶 pop_front_maxheap
int pop_front_maxheap(MHeap heap, ElemType *pElem)
{
assert(heap != NULL);
if (empty_maxheap(heap)) {
return FAILURE;
}
if (pElem != NULL) {
*pElem = heap->elems[0];
}
heap->elems[0] = heap->elems[--heap->size]; // 用最后一个元素替换堆顶
pushdown_maxheap(heap->elems, 0, heap->size); // 向下维护堆
return SUCCESS;
}
删除指定位置元素 remove_maxheap
int remove_maxheap(MHeap heap, size_t pos, ElemType *pElem)
{
assert(heap != NULL);
if (heap->size == 0 || pos == 0 || pos > heap->size) {
return FAILURE;
}
if (pElem != NULL) {
*pElem = heap->elems[pos - 1];
}
ElemType elem = heap->elems[--heap->size]; // 用最后一个元素替换要删除的元素
heap->elems[pos - 1] = elem;
pushdown_maxheap(heap->elems, pos - 1, heap->size); // 向下调整
// elem = heap->elems[index]; // 防止向下调整过后 元素变化
if (elem == heap->elems[pos - 1]) { // 如果没有向下调整过 就向上调整
pushup_maxheap(heap->elems, pos - 1); // 向上调整
}
return SUCCESS;
}
删除最后一个元素 pop_back_maxheap
int pop_back_maxheap(MHeap heap, ElemType *pElem)
{
assert(heap != NULL);
if (empty_maxheap(heap)) {
return FAILURE;
}
if (pElem != NULL) {
*pElem = heap->elems[--heap->size]; // 直接删除
}
return SUCCESS;
}