在C++中,可以通过std::priority_queue来使用堆。

堆的C语言实现:

heap.c

 /** @file heap.c
* @brief 堆,默认为小根堆,即堆顶为最小.
*/
#include <stdlib.h> /* for malloc() */
#include <string.h> /* for memcpy() */
typedef int heap_elem_t; // 元素的类型 /**
* @struct
* @brief 堆的结构体
*/
typedef struct heap_t
{
  int size;  /** 实际元素个数 */
  int capacity;   /** 容量,以元素为单位 */
  heap_elem_t *elems;  /** 堆的数组 */
  int (*cmp)(const heap_elem_t*, const heap_elem_t*);
}heap_t; /** 元素的比较函数 */
/** 基本类型(如 int, long, float, double)的比较函数 */
int cmp_int(const int *x, const int *y)
{
  const int sub = *x - *y;
  if(sub > )
  {
    return ;
  }
  else if(sub < )
  {
    return -;
  }
  else
  {
    return ;
  }
} /**
* @brief 堆的初始化.
* @param[out] h 堆对象的指针
* @param[out] capacity 初始容量
* @param[in] cmp cmp 比较函数,小于返回-1,等于返回 0
* 大于返回 1,反过来则是大根堆
* @return 成功返回 0,失败返回错误码
*/
int heap_init(heap_t *h, const int capacity, int (*cmp)(const heap_elem_t*, const heap_elem_t*))
{
  h->size = ;
  h->capacity = capacity;
  h->elems = (heap_elem_t*)malloc(capacity * sizeof(heap_elem_t));
  h->cmp = cmp;
  return ;
} /**
* @brief 释放堆.
* @param[inout] h 堆对象的指针
* @return 成功返回 0,失败返回错误码
*/
int heap_uninit(heap_t *h)
{
  h->size = ;
  h->capacity = ;
  free(h->elems);
  h->elems = NULL;
  h->cmp = NULL;
  return ;
} /**
* @brief 判断堆是否为空.
* @param[in] h 堆对象的指针
* @return 是空,返回 1,否则返回 0
*/
int heap_empty(const heap_t *h)
{
  return h->size == ;
} /**
* @brief 获取元素个数.
* @param[in] s 堆对象的指针
* @return 元素个数
*/
int heap_size(const heap_t *h)
{
  return h->size;
} /*
* @brief 小根堆的自上向下筛选算法.
* @param[in] h 堆对象的指针
* @param[in] start 开始结点
* @return 无
*/
void heap_sift_down(const heap_t *h, const int start)
{
  int i = start;
  int j;
  const heap_elem_t tmp = h->elems[start];
  for(j = * i + ; j < h->size; j = * j + )
  {
    if(j < (h->size - ) && h->cmp(&(h->elems[j]), &(h->elems[j + ])) > )
    {
      j++; /* j 指向两子女中小者 */
    }
    // tmp <= h->data[j]
    if(h->cmp(&tmp, &(h->elems[j])) <= )
    {
      break;
    }
    else
    {
      h->elems[i] = h->elems[j];
      i = j;
    }
  }
  h->elems[i] = tmp;
} /*
* @brief 小根堆的自下向上筛选算法.
* @param[in] h 堆对象的指针
* @param[in] start 开始结点
* @return 无
*/
void heap_sift_up(const heap_t *h, const int start)
{
  int j = start;
  int i= (j - ) / ;
  const heap_elem_t tmp = h->elems[start];
  
  while(j > )
  {
    // h->data[i] <= tmp
    if(h->cmp(&(h->elems[i]), &tmp) <= )
    {
      break;
    }
    else
    {
      h->elems[j] = h->elems[i];
      j = i;
      i = (i - ) / ;
    }
  }
  h->elems[j] = tmp;
} /**
* @brief 添加一个元素.
* @param[in] h 堆对象的指针
* @param[in] x 要添加的元素
* @return 无
*/
void heap_push(heap_t *h, const heap_elem_t x)
{
  if(h->size == h->capacity)
  {
    /* 已满,重新分配内存 */
    heap_elem_t* tmp = (heap_elem_t*)realloc(h->elems, h->capacity * * sizeof(heap_elem_t));
    h->elems = tmp;
    h->capacity *= ;
  }
  h->elems[h->size] = x;
  h->size++;
  heap_sift_up(h, h->size - );
} /**
* @brief 弹出堆顶元素.
* @param[in] h 堆对象的指针
* @return 无
*/
void heap_pop(heap_t *h)
{
  h->elems[] = h->elems[h->size - ];
  h->size --;
  heap_sift_down(h, );
} /**
* @brief 获取堆顶元素.
* @param[in] h 堆对象的指针
* @return 堆顶元素
*/
heap_elem_t heap_top(const heap_t *h)
{
  return h->elems[];
}

堆的C语言实现的更多相关文章

  1. 堆排序(大顶堆、小顶堆)----C语言

    堆排序 之前的随笔写了栈(顺序栈.链式栈).队列(循环队列.链式队列).链表.二叉树,这次随笔来写堆 1.什么是堆? 堆是一种非线性结构,(本篇随笔主要分析堆的数组实现)可以把堆看作一个数组,也可以被 ...

  2. 浅谈C#堆栈与托管堆的工作方式(转)

    C#初学者经常被问的几道辨析题,值类型与引用类型,装箱与拆箱,堆栈,这几个概念组合之间区别,看完此篇应该可以解惑. 俗话说,用思想编程的是文艺程序猿,用经验编程的是普通程序猿,用复制粘贴编程的是2B程 ...

  3. 实用算法系列之RT-Thread链表堆管理器

    [导读] 前文描述了栈的基本概念,本文来聊聊堆是怎么会事儿.RT-Thread 在社区广受欢迎,阅读了其内核代码,实现了堆的管理,代码设计很清晰,可读性很好.故一方面了解RT-Thread内核实现,一 ...

  4. .net基础复习之一

    一.             ADO 与ADO.NET两种数据访问方式区别? 1. ADO与ADO.NET简介ADO与ADO.NET既有相似也有区别,他们都能够编写对数据库服务器中的数据进行访问和操作 ...

  5. 深入C#内存管理来分析值类型&引用类型,装箱&拆箱,堆栈几个概念组合之间的区别

    C#初学者经常被问的几道辨析题,值类型与引用类型,装箱与拆箱,堆栈,这几个概念组合之间区别,看完此篇应该可以解惑. 俗话说,用思想编程的是文艺程序猿,用经验编程的是普通程序猿,用复制粘贴编程的是2B程 ...

  6. C++数组和指针

    <C++ Primer 4th>读书摘要 与 vector 类型相似,数组也可以保存某种类型的一组对象:而它们的区别在于,数组的长度是固定的.数组一经创建,就不允许添加新的元素.指针则可以 ...

  7. Java基本类型与包装类

    存储方式及位置的不同,基本类型是直接存储变量的值保存在堆栈中能高效的存取,封装类型需要通过引用指向实例,具体的实例保存在堆中   Java语言提供了八种基本类型.六种数字类型(四个整数型,两个浮点型) ...

  8. 7、存储类 & 作用域 & 生命周期 & 链接属性

    概念解析 存储类 存储类就是存储类型,也就是描述C语言变量在何种地方存储. 内存有多种管理方法:栈.堆.数据段.bss段..text段······一个变量的存储类属性就是描述这个变量存储在何种内存段中 ...

  9. [No0000B5]C# 类型基础 值类型和引用类型 及其 对象判等 深入研究1

    引言 本文之初的目的是讲述设计模式中的 Prototype(原型)模式,但是如果想较清楚地弄明白这个模式,需要了解对象克隆(Object Clone),Clone其实也就是对象复制.复制又分为了浅度复 ...

随机推荐

  1. JAVA在Windows使用apache commons-csv导出CSV解决方案

    一.添加依赖到pom.xml <!-- https://mvnrepository.com/artifact/commons-io/commons-io --> <dependenc ...

  2. Shell获取某目录下所有文件夹的名称

    查看目录下面的所有文件: #!/bin/bash cd /目标目录 for file in $(ls *) do echo $file done 延伸的方法,查看目录下面的所有目录 #!/bin/ba ...

  3. JSR-303 Bean Validation 介绍及 Spring MVC 服务端验证最佳实践

    任何时候,当要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情. 应用程序必须通过某种手段来确保输入参数在上下文来说是正确的. 分层的应用在很多时候,同样的数据验证逻辑会出现在不同的层, ...

  4. Objc的底层并发API

    本文由webfrogs译自objc.io,原文作者Daniel Eggert.转载请注明出处! 小引 本篇英文原文所发布的站点objc.io是一个专门为iOS和OS X开发者提供的深入讨论技术的平台, ...

  5. Jenkins常用插件

    Generic Webhook Trigger Plugin触发器webhook用户触发构建 Deploy to container Plugin部署到tomcat Gradle Plugin Gra ...

  6. 判断js数组包是否包含某个元素

    要判断数组中是否包含某个元素,从原理来来说,就是遍历整个数组,然后判断是否相等,我们来造个轮子,名字就山寨PHP的数组函数in_array() Array.prototype.in_array = f ...

  7. 【转】java 读取 excel 2003 或 excel 2007

    package com.my.login; import java.io.File; import java.io.FileInputStream; import java.io.IOExceptio ...

  8. Hive SQL grouping sets 用法

    概述 GROUPING SETS,GROUPING__ID,CUBE,ROLLUP 这几个分析函数通常用于OLAP中,不能累加,而且需要根据不同维度上钻和下钻的指标统计,比如,分小时.天.月的UV数. ...

  9. vs get set快捷键

    vs get set快捷键 光标放在空白处输入prop,然后tab两次,修改类型和名称即可

  10. vue环境配置脚手架环境搭建vue工程目录

    首先在初始化一个vue项目之前,我们需要下载node.js,并且安装! 下载地址: nodejs.cn/download 安装完成之后,windows+r 运行命令 cmd  输入node -v  检 ...