作者: TomyZhang | 来源:发表于2019-05-12 14:53 被阅读0次

一、概念

堆是一种基于完全二叉树的数据结构,当一棵完全二叉树满足下列条件时即称为堆:
每个父结点都大于等于(或者小于等于)它的两个子结点。
大于等于的情况称为大根堆,小于等于的情况称为小根堆。

完全二叉树:

  • 每个结点最多有两个子结点(二叉)。
  • 除了最底层,其他每一层都必须填满,最底层也需要从左到右依次填入数据。
小根堆

堆的应用:

  • 构建优先队列
  • 支持堆排序
  • 快速找出一个集合中的最小值(或者最大值)

堆的存储:
堆的存储通过数组来实现,由于其满足完全二叉树的性质,则对于第i个结点(i从0开始算):
父结点:(i-1)/2 // 为负数时则说明父结点不存在
左右子结点:(i * 2 + 1) 和 (i * 2 + 2)

堆的存储

二、相关操作

  • 插入
    对于一个数组存储的堆,如果加入了新元素,必须想办法保持堆的特性:
    1.完全二叉。
    2.大根堆:父结点大于等于其子结点。小根堆:父结点小于等于其子结点。
    即分为两步:
    1.将新的数放入数组尾部。
    2.将最后一个数向上调整。

  • 删除
    堆结构仅支持从堆顶进行删除操作,每次都能够删除最小的元素(小根堆)或者最大的元素(大根堆)。删除以后堆结构即遭到破坏(缺失了首元素),此时可以通过以下两步恢复:
    1.将最后一个元素放到堆顶。
    2.将堆顶元素向下调整。

  • 堆排序
    由于堆的顶部总是最小的数(小根堆)或者最大的数(大根堆),只需要每次将顶部的数取出,然后再将堆调整为最小堆或者最大堆即可。
    取出一个数,最多需要调整logN次。有N个数需要取出,所以堆排序的时间复杂度为NlogN。

堆相关操作

三、实现

#include<stdio.h> 
#define MAX 100

int data[MAX];
int dataIndex = 0;

void swap(int parent, int pos) {
    int temp;
    temp = data[parent];
    data[parent] = data[pos];
    data[pos] = temp;
}

void fix_up() {
    int pos = dataIndex - 1;
    int value = data[pos];
    int parent = (pos - 1) / 2;

    while (parent >= 0 && value < data[parent]) {  //当前结点有父母且值小于父母
        swap(parent, pos);
        pos = parent;
        parent = (pos - 1) / 2;
        value = data[pos];
    }
}

void heap_insert(int val)
{
    data[dataIndex++] = val; //1.放到尾部
    fix_up(); //2.小根堆,向上调整
}

void fix_down(){
    if (dataIndex <= 0) {
        return;
    }
    
    int pos = 0;
    int value = data[pos];
    int left = pos * 2 + 1;
    int right = left + 1;

    while (left < dataIndex) { //左边的结点无越界 
        int refValue;
        int refPos;
        if (right < dataIndex) { //右边的结点无越界 
            refValue = data[left] < data[right] ? data[left] : data[right]; //获取子结点中较小的值 
            refPos = data[left] < data[right] ? left : right; //获取子结点中较小的值的位置 
        } else { //右边的结点有越界 
            refValue = data[left];
            refPos = left;
        }
        if (value > refValue) {
            swap(pos, refPos);
        } else {
            break;
        }
        
        pos = refPos;
        left = pos * 2 + 1;
        right = left + 1; 
        value = data[pos];
    }
}

void heap_pop() {
    if(dataIndex <= 0) {
        return;
    }
    
    data[0] = data[dataIndex - 1]; // 1.把尾部的值放到头部
    dataIndex--;
    fix_down(); // 2.小根堆,向下调整
}

void preOrder(int pos) {
    if(pos < 0 || pos > dataIndex-1) {
        return;
    }
    printf("%d ", data[pos]);
    preOrder(pos * 2 + 1);
    preOrder(pos * 2 + 2);
}

void main() {
    heap_insert(15);
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_insert(8);
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_insert(10);
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_insert(4);
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_insert(1);
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_insert(7);
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_insert(30);
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_pop();
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_pop();
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_pop();
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_pop();
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_pop();
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_pop();
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_pop();
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
    heap_pop();
    printf("preOrder: ");
    preOrder(0);
    printf("\n");
}

相关文章

  • 堆 - 堆的应用

    堆有三个典型的应用场景:实现优先队列、求 Top K 、求中位数 实现优先队列 优先队列:队列的性质是先进先出,但...

  • 二叉堆是一棵满二叉树,父节点的值大于子节点。 用数组存储二叉堆,假如一个节点的下标为k,那么这个节点的左孩子就是2...

  • 应用: 排序,从小到大用最大堆,从大到小用最小堆 选出元素中的 top k 个top k 个最小数:数组前k个元素...

  • 完全二叉树 二叉堆 二叉堆有最大堆和最小堆的区别,最大堆只保证每个节点的父节点大于当前节点,但不保证上一层节点的值...

  • 堆的定义: n个元素序列{k1,k2,...,ki,...,kn},当且仅当满足下列关系时称之为堆: (ki...

  • http://bubkoo.com/2014/01/14/sort-algorithm/heap-sort/ 1 ...

  • 堆 …

    南山南,北山北,南山有谷堆,北山有花蕾,山坡下,大道中,野树停在石堆,秋风送,冷雪飘,旅途空旷叶儿飞,时间漫,皱纹...

  • 题目:100w个数中找出最大的100个。 维护一个100个元素的小根堆即可。 或者直接维护一个用来存储当前最大的1...

网友评论

      本文标题:

      本文链接:https://www.haomeiwen.com/subject/egecaqtx.html