数据结构 堆(大根堆)

定义

  • 逻辑结构:完全二叉树
  • 物理(存储)结构:顺序表
  • 大根堆
    • 每一个节点元素的值都不小于左右子树的值
    • 根节点的元素最大
  • 小根堆
    • 每一个节点元素的值都不大于左右子树的值
    • 根节点的元素最小

下标从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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值