基本数据结构之堆

堆的定义

堆是一个完全二叉树或者近似的完全二叉树

堆的性质

  1. 父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。
  2. 每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。
堆的存储

一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2

堆的特点

插入元素和弹出堆顶元素的时间复杂度lg(n)

判断序列是不是堆

根据性质判断

比如输入序列15,30,22,93,52,71,89,15是根节点,可以看出满足性质,这是一个小根堆
                15
         30             22
    93       52    71        89

堆的C语言实现

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

//c++ 中的priority_queue就是一个堆

typedef int heap_elem; //堆的数据类型

/**
 * @author 韦轩
 * @time 2015/07/13
 * @brief 堆的基本结构
 *
 */
typedef struct heap
{
    int size; //实际元素个数
    int capacity;//堆的容量
    heap_elem* elements;//堆的存储数组
    int(*cmp)(const heap_elem*, const heap_elem*); //元素的比较函数
}heap;

/**
 * @author 韦轩
 * @time 2015/07/13
 * @brief 创建一个堆
 * @param capacity 容量
 * @param cmp,小于返回-1,等于返回0,大于返回1,反过来是大根堆
 * @return 成功返回堆对象的指针,否则为nullptr
 *
 */
heap* heap_create(const int capacity, int(*cmp)(const heap_elem*, const heap_elem*))
{
    heap* myheap = (heap*)malloc(sizeof(heap));

    myheap->size = 0;
    myheap->capacity = capacity;
    myheap->cmp = cmp;
    myheap->elements = (heap_elem*)malloc(capacity*sizeof(heap_elem));

    return myheap;
}

/**
 * @author 韦轩
 * @time 2015/07/13
 * @brief 销毁堆
 * @param
 * @return 无
 *
 */
void heap_destory(heap* myheap)
{
    free(myheap->elements);
    free(myheap);
}

/**
 * @author 韦轩
 * @time 2015/07/13
 * @brief 判断堆是否为空
 * @param
 * @return 返回true 是空,否则false
 *
 */
bool heap_empty(const heap* myheap)
{
    return myheap->size == 0;
}

/**
 * @author 韦轩
 * @time 2015/07/13
 * @brief 堆的元素的个数
 * @param
 * @return 返回元素的个数
 *
 */
int heap_size(const heap* myheap)
{
    return myheap->size;
}

/**
 * @author 韦轩
 * @time 2015/07/13
 * @brief 获取堆顶元素
 * @param
 * @return 返回堆顶元素
 *
 */

heap_elem heap_top(const heap* myheap)
{
    return myheap->elements[0];
}

/**
 * @author 韦轩
 * @time 2015/07/13
 * @brief 小根堆的自上而下的筛选算法
 * @param start 开始的结点
 * @return
 *
 */
void heap_sift_down(const heap* myheap, const int start)
{
    int i = start;
    int j;

    const heap_elem temp = myheap->elements[start];

    for (j = 2 * i + 1; j < myheap->size; j = 2 * j + 1)
    {
        if (j < myheap->size - 1 && myheap->cmp(&(myheap->elements[j]), &(myheap->elements[j + 1]))>0)
        {
            j++;//j指向两子女中的较小者
        }
        if (myheap->cmp(&temp, &(myheap->elements[j]))<=0)
        {
            break;
        }
        else
        {
            myheap->elements[i] = myheap->elements[j];
            i = j;
        }
    }
    myheap->elements[i] = temp;
}

/**
 * @author 韦轩
 * @time 2015/07/13
 * @brief 小根堆自下而上的筛选算法
 * @param  start 起始位置
 * @return
 *
 */
void heap_sift_up(const heap* myheap, const int start)
{
    int j = start;
    int i = (j - 1) / 2;
    const heap_elem temp = myheap->elements[start];

    while (j > 0)
    {
        if (myheap->cmp(&(myheap->elements[i]), &temp) <= 0)
        {
            break;
        }
        else
        {
            myheap->elements[j] = myheap->elements[i];
            j = i;
            i = (i - 1) / 2;
        }
    }
    myheap->elements[j] = temp;
}

/**
 * @author 韦轩
 * @time 2015/07/13
 * @brief 添加元素
 * @param
 * @return
 *
 */
void heap_push(heap* myheap, const heap_elem x)
{
    //堆已满,重新分配内存
    if (myheap->size == myheap->capacity)
    {
        heap_elem* temp =(heap_elem*)realloc(myheap->elements, myheap->capacity * 2 * sizeof(heap_elem));
        myheap->elements = temp;
        myheap->capacity *= 2;
    }
    myheap->elements[myheap->size] = x;
    myheap->size++;

    heap_sift_up(myheap, myheap->size - 1);
}

/**
* @author 韦轩
* @time 2015/07/13
* @brief 弹出栈顶元素
* @param
* @return
*
*/
void heap_pop(heap* myheap)
{
    myheap->elements[0] = myheap->elements[myheap->size - 1];
    myheap->size--;

    heap_sift_down(myheap, 0);
}

/**
 * @author 韦轩
 * @time 2015/07/13
 * @brief 基本数据类型的比较
 * @param
 * @return
 *
 */
int cmp(const int* data1, const int* data2)
{
    const int ret = *data1 - *data2;
    if (ret < 0)
        return -1;
    else if (ret > 0)
        return 1;
    else
        return 0;
}

/**
 * @author 韦轩
 * @time 2015/07/13
 * @brief 打印堆,默认是int
 *
 */
void heap_print(const heap* myheap)
{
    if (myheap == NULL)
        return;
    for (int i = 0; i < myheap->size; i++)
    {
        printf_s("%d\t", myheap->elements[i]);
    }
}
int main()
{
    heap* myheap = heap_create(6, cmp);

    heap_push(myheap, 10);
    heap_push(myheap, 3);
    heap_push(myheap, 2);
    heap_push(myheap, 5);
    heap_push(myheap, 1);

    puts("初始...\n");
    heap_print(myheap);

    puts("插入100,20...\n");
    heap_push(myheap, 100);
    heap_push(myheap,20);

    heap_print(myheap);

    puts("删除堆顶元素...\n");

    heap_pop(myheap);

    heap_print(myheap);

    heap_destory(myheap);

    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-01 14:55:24

基本数据结构之堆的相关文章

数据结构学习——堆

1 基本介绍 堆数据结构是一种数组对象,它可以被视为一颗完全二叉树.堆的访问可以通过三个函数来进行即, parent(i) return floor(i/2); left(i) return 2i; right(i) return 2i + 1; left操作可以通过一步左移操作完成,right操作可以通过左移并在地位+1实现,parent操作则可以通过把i右移一位得到.在实现中通常会使用宏或者内联函数来实现这三个操作. 二叉堆有两种,最大堆和最小堆.对于最大堆有 A[i] >= A[left(

数据结构之堆的插入、取值、排序(细致讲解+图片演示)

数据结构之堆(Heap):插入.取值.排序. 堆是一种数据结构,分为最小堆和最大堆,可以用二叉树来表示. 在二叉树的任意的一个三角结构中(一个父节点,两个子节点),需要满足以下两个条件: 1.父节点要是最小的,就是最小堆(或最大的,就是最大堆),两个子节点之间没有要求 2.数据插入的顺序是一层一层的,只有上一层存满,才会有下一层 下面我们以图片的形式演示最小堆的插入.取值.和排序操作,只要知道最小堆的原理,那么最大堆也就明白了. 假设我们有一个原始的最小堆如下: 插入操作: 当插入一个新值时,首

《ACM/ICPC 算法训练教程》读书笔记一之数据结构(堆)

书籍简评:<ACM/ICPC 算法训练教程>这本书是余立功主编的,代码来自南京理工大学ACM集训队代码库,所以小编看过之后发现确实很实用,适合集训的时候刷题啊~~,当时是听了集训队final的意见买的,感觉还是不错滴. 相对于其他ACM书籍来说,当然如书名所言,这是一本算法训练书,有着大量的算法实战题目和代码,尽管小编还是发现了些许错误= =,有部分注释的语序习惯也有点不太合我的胃口.实战题目较多是比较水的题,但也正因此才能帮助不少新手入门,个人认为还是一本不错的算法书,当然自学还是需要下不少

【数据结构】堆的实现(包括:默认成员函数,插元素push,删元素pop,访问根节点top,判空,大小)

在数据结构里,堆是一类很重要的结构.堆结构是一组数组对象,我们可以把它当作是一颗完全二叉树. 最大堆:堆里每一个父亲节点大于它的子女节点. 最小堆:堆里每一个父亲节点小于它的子女节点. 如图就是一个最大堆: 实现代码时我的测试序列是:int a[] = { 10, 11, 13, 12, 16, 18, 15, 17, 14, 19 }; 我们把它的图画出来,便于分析. 实现代码如下: 建立头文件heap.hpp #define _CRT_SECURE_NO_WARNINGS 1 #includ

数据结构之堆(Heap)的实现

堆数据结构是一种数组对象,它可以被视为一棵完全二叉树结构,所以堆也叫做二叉堆. 二叉堆满足二个特性: 1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值. 2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆). 当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆.当父结点的键值总是小于或等于   任何一个子节点的键值时为最小堆. 最大堆和最小堆是堆数据结构的重点.堆排序中使用特别的多. 堆的存储一般是用一个数组实现的,当然也可以用链式存储,但是特别麻烦. 如下我

【数据结构】堆

堆 这种数据结构.一般堆用来实现优先级队列.优先级队列:和通常的栈和队列一样,只不过里面的每个元素都有一个"优先级",在处理的时候,首先处理优先级最高的.通常包含三个操作getMax/delMax/insert 栈和队列算是优先级队列的特例. 使用其他数据结构均不能同时在O(lgn)的复杂度下完成.至少有一种操作要耗时O(nlgn).比如链表的插入操作O(1),但是获取最大值必须遍历链表. 可以使用BBST以上三个操作达到最好的时间复杂度O(lgn).事实上没必要用那么高端的数据结构来

[数据结构]最小堆的类模板实现

堆数据结构是一种数组对象,它可以被视为一科完全二叉树结构. 它的特点是父节点的值大于(小于)两个子节点的值(分别称为最大堆和最小堆).它常用于管理算法执行过程中的信息,应用场景包括堆排序,优先队列等. 1.根结点若有子树,则子树一定也是堆. 2.根结点一定大于(或小于)子结点. 因为要求堆必须是完全二叉树,所以可以用线性的数据结构,比如数组,来实现堆. 利用数组实现,则对于长为N的堆中的元素从0到N-1排列,有: i的父结点:Parent(i)=(i+1)/2-1 i的左叶子:Left(i)=(

【数据结构】堆的删除

题目 实现在最小堆中删除给定序号为pos的元素,并由x返回,删除成功返回true,失败返回false.(注意:删除后要保持数据结构是最小堆.) 算法实现 在最小堆中删除给定序号为pos的元素,我们可以先删除该元素后将堆中最后一个元素补到该位子,然后向下调整为堆,在从该位置向上调整为堆. 1 如果堆空返回false 2 x = heap[pos]; // 返回元素 3 heap[pos] = heap[currentSize - 1]; //最后元素填补到pos结点 4 currentSize--

01玩转数据结构_08_堆和优先队列

堆: 树这种结构 本身在计算机科学领域 占有很重要的地位,这种数据结构之所以占有重要的地位,不仅仅是因为二分搜索树这样的一种结构, 是树本身这种形状可以产生很多拓展,对于不同的问题 ,我们可以稍微改变 或者 限制树这种数据结构的性质,从而产生不同的数据结构,高效的解决不同的问题, 从节开始,将会有四个章节介绍 四个不同的例子,它们分别是堆,线段树,字典树 以及 并查集 ,通过这些不同的树的结构,我们可以领会到 数据结构的灵活之处, 什么是优先队列: 优先队列(相对 高层的数据结构) 是 出队,入