Binary Heap(二叉堆)

Binary Heap (二叉堆)


1. 二叉堆的定义

  在计算机科学中,二叉堆二叉树形状的堆结构。二叉堆是最常见的实现优先级队列的方法,它与优先级队列紧密相连,一起应用到诸多地方,在很多主流语言的标准算法库中都能看到它们的身影。同时它也是很多算法中需要用到的底层数据结构,能够快速地掌握这些已有的标准库和类,能够很高效地实现诸多算法。

  • 其空间复杂度和相关操作的时间复杂度如下表所示:

AlgorithmAverageWorst Case
SpaceO(n)O(n)
SearchO(n)O(n)
InsertO(1)O(log n)
DeleteO(log n)O(log n)
PeekO(1)O(1)

2. 二叉堆的性质

  二叉堆的是一个具有堆性质的完全二叉树,因此二叉堆具备了完全二叉树和堆的全部特性,实现起来非常容易,也是程序员必须要掌握的基本数据结构。

  • 最大堆示例
    最大堆示例

  • 完全二叉树: 完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。只有最下面的两层结点度能够小于2,并且最下面一层的结点都集中在该层最左边的若干位置。完全二叉树是一种效率很高的数据结构,通常采用数组形式存储,可以快速计算出一个节点的父子节点,同时不需要额外存储索引信息。

  • 堆性质: 堆性质是指树中的任意节点的取值,均比其字节点的取值大,称为最大堆。(或小,称为最小堆)这个是基于二叉堆获得节点取值对应关系的重要依据,是体现优先级的地方。


3. C语言实现二叉堆的基本操作(指针操作)

#include <stdio.h>
#include <stdlib.h>

#define ARRAY_LENGTH(x) (sizeof(x) / sizeof(x[0]))

int int_less(const void *key1, const void *key2) {
    if (*((int *) key1) < *((int *) key2)) return 1;
    else return 0;
}

void int_swap(void *a, void *b) {
    int temp;
    temp = *(int*)a;
    *(int*)a = *(int*)b;
    *(int*)b = temp;
}

void **array_to_data(int *array, int n) {
    void **data = (void **) malloc(sizeof(void *) * n);
    for (int i = 0; i < n; i++) {
        data[i] = (array+i);
    }
    return data;
}

void output_int_array(int *data, int n) {
    int *p = data;
    for (int i=0; i<n; i++) {
        printf("%d, ", *(p++));
    }
    printf("\n");
}

void output_int_data(void **data, int n) {
    void **p = data;
    for (int i=0; i<n; i++) {
        printf("%d, ", *((int *) *(p++)));
    }
    printf("\n");
}


// adds an element to a heap
void push_heap(void **data, int *len, const int capacity, void *x,
               int (*compare)(const void *key1,
                              const void *key2),
               void (*swap)(void *a, void *b)) {
    if (*len >= capacity) return;
    // from bottom shift to top
    int n = *len; *len = *len + 1;
    data[n] = x;
    while (n != 0) {
        int p = (n-1) / 2;
        if (! compare(data[p], data[n])) {
            swap(data[p], data[n]);
            n = p;
        } else {
            break;
        }
    }
}

// creates a heap out of a range of elements
void make_heap(void **data, const int n,
               int (*compare)(const void *key1,
                              const void *key2),
               void (*swap)(void *a, void *b)) {

    int len = 0;
    while (len < n) {
        push_heap(data, &len, n, data[len], compare, swap);
    }        

}

// removes the largest element from a max heap
void *pop_heap(void **data, int *len,
               int (*compare)(const void *key1,
                              const void *key2),
               void (*swap)(void *key1, void *key2)) {
    if (*len <= 0) return NULL;

    // from top to bottom
    int n = 0;
    void *x = data[n]; *len = *len - 1;
    data[n] = data[*len];
    int c, c1, c2;
    while ((c1 = 2*n + 1) < *len) {
        c = c1;
        if (((c2 = 2 * (n+1)) < *len) &&
            ! compare(data[c1], data[c2])) {
            c = c2;
        }
        if (! compare(data[n], data[c])) {
            swap(data[n], data[c]);
            n = c;
        } else {
            break;
        }
    }
    return x;
}

void test_make_heap() {
    int array[] = {3, 5, 8, 2, 7, 4, 1, 6, 9};
    int n = ARRAY_LENGTH(array);
    output_int_array(array, n);

    void **data = array_to_data(array, n);
    output_int_data(data, n);

    make_heap(data, n, int_less, int_swap);
    output_int_data(data, n);

    int len = n;
    void *x = NULL;
    while (len > 0) {
        x = pop_heap(data, &len, int_less, int_swap);
        printf("%d, ", *(int *)x);
    }
    printf("\n");    

    free(data);
}

int main(void) {

    test_make_heap();

    return 0;
}

4. 标准算法库与工具类

5. 二叉堆的应用

  二叉堆非常适合解决在连续的插入和删除操作中,快读定位最大值或最小值的问题。在很多贪心算法中,都需要取得当前时刻的最大值或最小值,二叉堆与贪心算法的结合尤其紧密。

1). 堆排序
2). 优先级队列
3). Top K Problem


6. leetcode 刷题

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
二叉排序树(Binary Search Tree,BST)和堆(Heap)是两种常见的数据结构,它们有以下区别: 1. 结构特点: - 二叉排序树:BST是一种二叉树,其中每个节点的值大于其左子树中的所有节点的值,小于其右子树中的所有节点的值。 - 堆:堆是一种完全二叉树,其中每个节点的值都大于或等于其子节点的值(最大堆),或者每个节点的值都小于或等于其子节点的值(最小堆)。 2. 插入和删除操作: - 二叉排序树:在BST中插入和删除节点的操作相对简单,只需按照特定规则找到合适的位置进行插入或删除即可。 - 堆:堆的插入和删除操作相对复杂,需要维护堆的性质。插入操作会将新元素放在堆的末尾,并通过上浮操作将其调整到合适位置;删除操作会将堆顶元素移除,并通过下沉操作将新的堆顶元素调整到合适位置。 3. 应用场景: - 二叉排序树:BST常用于实现动态集合,可以高效地支持查找、插入和删除操作。它还可以用于实现有序遍历等操作。 - 堆:堆常用于实现优先队列,可以高效地找到最大或最小元素。它还可以用于排序算法(如堆排序)和图算法(如Dijkstra算法)等。 4. 时间复杂度: - 二叉排序树:在平衡的情况下,BST的查找、插入和删除操作的平均时间复杂度为O(log n),但在最坏情况下可能退化为链表,时间复杂度为O(n)。 - 堆:堆的插入和删除操作的时间复杂度为O(log n),其中n为堆中元素的个数。堆的查找操作不是其主要优势,时间复杂度为O(n)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值