堆的C语言实现
在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语言实现的更多相关文章
- 堆排序(大顶堆、小顶堆)----C语言
堆排序 之前的随笔写了栈(顺序栈.链式栈).队列(循环队列.链式队列).链表.二叉树,这次随笔来写堆 1.什么是堆? 堆是一种非线性结构,(本篇随笔主要分析堆的数组实现)可以把堆看作一个数组,也可以被 ...
- 浅谈C#堆栈与托管堆的工作方式(转)
C#初学者经常被问的几道辨析题,值类型与引用类型,装箱与拆箱,堆栈,这几个概念组合之间区别,看完此篇应该可以解惑. 俗话说,用思想编程的是文艺程序猿,用经验编程的是普通程序猿,用复制粘贴编程的是2B程 ...
- 实用算法系列之RT-Thread链表堆管理器
[导读] 前文描述了栈的基本概念,本文来聊聊堆是怎么会事儿.RT-Thread 在社区广受欢迎,阅读了其内核代码,实现了堆的管理,代码设计很清晰,可读性很好.故一方面了解RT-Thread内核实现,一 ...
- .net基础复习之一
一. ADO 与ADO.NET两种数据访问方式区别? 1. ADO与ADO.NET简介ADO与ADO.NET既有相似也有区别,他们都能够编写对数据库服务器中的数据进行访问和操作 ...
- 深入C#内存管理来分析值类型&引用类型,装箱&拆箱,堆栈几个概念组合之间的区别
C#初学者经常被问的几道辨析题,值类型与引用类型,装箱与拆箱,堆栈,这几个概念组合之间区别,看完此篇应该可以解惑. 俗话说,用思想编程的是文艺程序猿,用经验编程的是普通程序猿,用复制粘贴编程的是2B程 ...
- C++数组和指针
<C++ Primer 4th>读书摘要 与 vector 类型相似,数组也可以保存某种类型的一组对象:而它们的区别在于,数组的长度是固定的.数组一经创建,就不允许添加新的元素.指针则可以 ...
- Java基本类型与包装类
存储方式及位置的不同,基本类型是直接存储变量的值保存在堆栈中能高效的存取,封装类型需要通过引用指向实例,具体的实例保存在堆中 Java语言提供了八种基本类型.六种数字类型(四个整数型,两个浮点型) ...
- 7、存储类 & 作用域 & 生命周期 & 链接属性
概念解析 存储类 存储类就是存储类型,也就是描述C语言变量在何种地方存储. 内存有多种管理方法:栈.堆.数据段.bss段..text段······一个变量的存储类属性就是描述这个变量存储在何种内存段中 ...
- [No0000B5]C# 类型基础 值类型和引用类型 及其 对象判等 深入研究1
引言 本文之初的目的是讲述设计模式中的 Prototype(原型)模式,但是如果想较清楚地弄明白这个模式,需要了解对象克隆(Object Clone),Clone其实也就是对象复制.复制又分为了浅度复 ...
随机推荐
- mipmap和drawable文件夹的区别
在Android上创建工程,会默认创建mipmap文件夹.之前在Eclipse上创建的是drawable的文件夹.那么这两个有什么区别呢? 问题: I'm working with android s ...
- MDX Cookbook 08 - 基于集合上的迭代递归
递归的应用有时是非常重要的,特别在迭代一个集合的时候.为什么这么说呢?原因在于迭代在MDX中的使用是基于集合函数的,像 GENERATE() 它们都需要遍历整个集合.但是如果这个集合非常的庞大,我们仅 ...
- SQL Server为字段添加默认值
SQL Server为字段添加默认值 if not exists ( select * from sys.columns as c join sys.objects as o on c.default ...
- 使用Github添加标签
Github为我们提供了在页面上进行编辑发行版本的方式,如下图所示: 在Github上为项目打tag可在release页面,选择创建新tag并按下图所示填写即可.删除tag也同理.
- PL/SQL学习笔记之循环语句
一:基本循环 LOOP 循环体: 退出循环: )IF condition THEN exit; END IF; ) exit WHEN condition; END LOOP; 二:WHILE循环 W ...
- [Python]编码声明:是coding:utf-8还是coding=urf-8呢
推荐: #!/usr/bin/env python3 # -*- coding: utf-8 -*- 我们知道在Python源码的头文件中要声明编码方式,如果你不只是会用到ascii码,很多人都写得都 ...
- [转]BLAS简介
BLAS(Basic Linear Algebra Subprograms)是一组线性代数计算中通用的基本运算操作函数集合[1] .BLAS Technical (BLAST) Forum负责规范BL ...
- 12C -- ORA-12850: 无法在所有指定实例上分配从属进程: 需要 2, 已分配 1
使用客户端连接到oracle 12.2.0.1 rac数据库,报以下错误信息: ORA-12850: 无法在所有指定实例上分配从属进程: 需要 2, 已分配 1 因为没有mos账号,只好谷歌一下了.找 ...
- SNF快速开发平台MVC-EasyUI3.9之-WebApi和MVC-controller层接收的json字符串的取值方法和调用后台服务方法
最近项目组很多人问我,从前台页面传到后台controller控制层或者WebApi 时如何取值和运算操作. 今天就都大家一个在框架内一个取值技巧 前台JS调用代码: 1.下面是选中一行数据后右键点击时 ...
- SNF快速开发平台MVC-甘特图
上个月做了CS框架的甘特图样例,本月框架组人员又实现了BS的甘特图效果,而且效果也很不错哦 图形框可以直接拖拽调整时长时间: 新增节点: