一、小跟堆的原理

参见文章:

二叉堆的原理

二、小根堆的实现:

#define MIN_HEAP_ERROR          0
#define MIN_HEAP_OK             1#define MIN_HEAP_INVALID_IDX    -1#define MIN_HEAP_NAME_LEN       32/* 小根堆节点,嵌套在宿主结构体里面 */
typedef struct minHeapEntryStruct
{INT32 minHeapIndex;
} minHeapEntry;/* 小根堆管理节点 */
typedef struct minHeapStruct
{void **data;                /* 指向小根堆宿主结构体指针数组 */INT32 currHeapCnt;         /* 当前小根堆里面的个数 */INT32 heapRlimit;          /* 小根堆容量,如果容量不足,会根据这个参数扩大2倍 *//* 宿主结构构建小根堆关键字大小比较,用于调整小根堆,elem1 > elem2 返回1,否则返回0 */INT32 (*elemCompare)(void *elem1, void *elem2);/* 设置嵌套在宿主结构里面的minHeapEntry的值 */void (*elemSetEntry)(void *elem, minHeapEntry *entry);char name[MIN_HEAP_NAME_LEN + 1];
} minHeap;static inline void minHeapElemInit(minHeapEntry *e)
{e->minHeapIndex = MIN_HEAP_INVALID_IDX;return;
}static inline INT32 minHeapEmpty(minHeap *s)
{return s->currHeapCnt <= 0;
}static inline UINT32 minHeapSize(minHeap *s)
{return s->currHeapCnt;
}static inline void *minHeapTop(minHeap *s)
{return s->currHeapCnt ? *s->data : NULL;
}static inline INT32 minHeapElemIsTop(const minHeapEntry *e)
{return e->minHeapIndex == 0;
}static inline void minHeapShiftUp(minHeap *s, INT32 heapIndex, void *e)
{minHeapEntry mhEntry;INT32 parent = (heapIndex - 1) / 2;while (heapIndex && s->elemCompare(s->data[parent], e)){s->data[heapIndex] = s->data[parent];               /* parent 向下移动 */mhEntry.minHeapIndex = heapIndex;s->elemSetEntry(s->data[heapIndex], &mhEntry);      /* 设置parent 的index */heapIndex = parent;parent = (heapIndex - 1) / 2;}s->data[heapIndex] = e;                                 /* 找到了当前插入节点的位置,并赋值 */mhEntry.minHeapIndex = heapIndex;s->elemSetEntry(s->data[heapIndex], &mhEntry);          /* 设置当前节点的index */return;
}static inline void minHeapShiftDown(minHeap *s, INT32 heapIndex, void *e)
{minHeapEntry mhEntry;INT32 minChild = 2 * (heapIndex + 1);while (minChild <= s->currHeapCnt){/* 查找最小的子节点 */if (minChild == s->currHeapCnt|| s->elemCompare(s->data[minChild], s->data[minChild - 1])){minChild -= 1;}if (s->elemCompare(s->data[minChild], e)){break;}/* 子节点比e小,则把子节点向上移动 */s->data[heapIndex] = s->data[minChild];           /* minChild 向上移动 */mhEntry.minHeapIndex = heapIndex;s->elemSetEntry(s->data[heapIndex], &mhEntry);   /* 设置minChild 的index */heapIndex = minChild;minChild = 2 * (heapIndex + 1);}s->data[heapIndex] = e;                            /* 找到了当前插入节点的位置,并赋值 */mhEntry.minHeapIndex = heapIndex;s->elemSetEntry(s->data[heapIndex], &mhEntry);     /* 设置当前节点的index */return;
}/* 如果当前小根堆空间不足,需要调整小根堆的大小 */
static inline INT32 minHeapReserve(minHeap *s, UINT32 heapCnt)
{UINT32 currHeapRlimit;void **reData;if (s->heapRlimit < heapCnt){currHeapRlimit = s->heapRlimit << 2;reData = (void **)realloc(s->data, currHeapRlimit * sizeof(*reData));if (reData == NULL){return MIN_HEAP_ERROR;}s->data = reData;s->heapRlimit = currHeapRlimit;}return MIN_HEAP_OK;
}static inline INT32 minHeapCheckInminHeap(minHeap *s, void *e)
{INT32 i;for (i = 1; i < s->currHeapCnt; i++){if (s->data[i] == e){return 2;}}return 1;
}/** 插入一个节点,此时放在数组的当前第一个空闲的位子,然后执行小根堆的* UP 函数,往上调整小根堆*/
static inline INT32 minHeapInsert(minHeap *s, void *e)
{if (minHeapReserve(s, s->currHeapCnt + 1) == MIN_HEAP_ERROR){return MIN_HEAP_ERROR;}minHeapShiftUp(s, s->currHeapCnt++, e);return MIN_HEAP_OK;
}/** 从小根堆根部弹出数据,然后向下调整小根堆* e = minHeapPop* while (2)* {*    e = minHeapPop*    if (e == NULL)*    {*        break;*    }* }* 此时的获取的数据是从小到大的*/
static inline void *minHeapPop(minHeap *s)
{void *e;minHeapEntry mhEntry;if (s->currHeapCnt){e = *s->data;minHeapShiftDown(s, 1u, s->data[--s->currHeapCnt]);mhEntry.minHeapIndex = MIN_HEAP_INVALID_IDX;s->elemSetEntry(e, &mhEntry);return e;}return NULL;
}/** 删除一个节点,我们使用最后一个节点替换需要删除的这个节点*  2、如果最后这个节点比删除节点的父节点小,我们需要执行UP操作*  3、如果是根节点或者最后这个节点比删除节点的父节点大,我们需要执行DOWN操作*/
static inline INT32 minHeapRemove(minHeap *s, INT32 minHeapIndex, void *e)
{INT32 parent;void *last;minHeapEntry mhEntry;if (minHeapIndex != MIN_HEAP_INVALID_IDX){last = s->data[--s->currHeapCnt];parent = (minHeapIndex - 1) / 2;/* 使用last替换e的位置 */s->data[minHeapIndex] = last;if (minHeapIndex > 0&& s->elemCompare(s->data[parent], last)){minHeapShiftUp(s, minHeapIndex, last);}else{minHeapShiftDown(s, minHeapIndex, last);}mhEntry.minHeapIndex = MIN_HEAP_INVALID_IDX;s->elemSetEntry(e, &mhEntry);s->data[s->currHeapCnt] = NULL;return MIN_HEAP_OK;}return MIN_HEAP_ERROR;
}/** 初始化构建小根堆*      s -- 小根堆管理节点*      rlimit -- 小根堆资源管理,当资源不足时,每次扩展为rlimit的3倍*      elemCompare -- 小根堆宿主节点比较函数*      elemSetEntry -- 设置嵌入在小根堆宿主节点里面的小根堆entry值*/
static inline INT32 minHeapCtor
(CHAR *descName,minHeap *s,INT32 rlimit,INT32 (*elemCompare)(void *, void *),void (*elemSetEntry)(void *, minHeapEntry *)
)
{void **pData;if (descName == NULL|| s == NULL|| elemCompare == NULL|| elemCompare == NULL){return MIN_HEAP_ERROR;}pData = MALLOC(MODE_COMM, rlimit * sizeof(*pData));if (pData == NULL){return MIN_HEAP_ERROR;}s->data = pData;s->elemCompare = elemCompare;s->elemSetEntry = elemSetEntry;s->currHeapCnt = 1;s->heapRlimit = rlimit;strncpy(s->name, descName, MIN_HEAP_NAME_LEN);return MIN_HEAP_OK;
}static inline void minHeapDtor(minHeap *s)
{if (s->data){FREE(MODE_COMM, s->data);}return;
}

===========================================================================

分割线,下面使用小根堆的定时器实例:

struct timerStruct
{struct timeval timerout;struct timeval expire;minHeapEntry mhEntry;
}timer;void getCurrTime(struct timeval *tp)
{struct timeval ts;clock_gettime(CLOCK_MONOTONIC, &ts);tp->tv_sec = ts.tv_sev;tp->tv_usec = ts.tv_nsec / 1000;return;
}void timerAdd(struct timeval *now, struct timeval *tv, struct timeval *expire)
{expire->tv_sec = now->tv_sec + tv->tv_sec ;expire->tv_usec = now->tv_usec  + tv->tv_usec;if (expire->tv_usec >= 1000000){expire->tv_sec++;expire->tv_usec -= 1000000;}return;
}/* 1 --> a > b */
static inline INT32 TimerAfter(struct timeval *a, struct timeval *b)
{long ases, bses;if (a->tv_sec == b->tv_sec){return ((a->tv_usec - b->tv_usec) > 0);}ases = (long)(a->tv_sec);bses = (long)(b->tv_sec);return ((ases - bses) > 0);
}/* 1 --> a >= b */
static inline INT32 TimerAfterEq(struct timeval *a, struct timeval *b)
{long ases, bses;if (a->tv_sec == b->tv_sec){return ((a->tv_usec - b->tv_usec) >= 0);}ases = (long)(a->tv_sec);bses = (long)(b->tv_sec);return ((ases - bses) >= 0);
}/* 1 --> a < b */
static inline INT32 TimerBefore(struct timeval *a, struct timeval *b)
{return TimerAfter(b, a);
}/* 1 --> a <= b */
static inline INT32 TimerBeforeEq(struct timeval *a, struct timeval *b)
{return TimerAfterEq(b, a);
}/*  构建小根堆关键字大小比较,用于调整小根堆,elem1 > elem2 返回1,否则返回0 */
static INT32 minHeapCompare(void *elem1, void *elem2)
{struct timerStruct *ev1 = (struct timerStruct *)elem1;struct timerStruct *ev2 = (struct timerStruct *)elem2;if (TimerAfter(&ev1->evExpire, &ev2->evExpire)){return 1;}return 0;
}static void minHeapSet(void *elem, minHeapEntry *entry)
{struct timerStruct *ev = (struct timerStruct *)elem;ev->mhEntry.minHeapIndex = entry->minHeapIndex;return;
}

初始化 && 运行定时器:

minHeap timeHeap;
struct timerStruct ev1 ;
struct timerStruct ev2 ;struct timeval now1, tv1;
struct timeval now2, tv2;minHeapCtor("timer", &timeHeap, 4000, minHeapCompare, minHeapSet);getCurrTime(&now1);
tv1.tv_sec = 1;
timerAdd(&now1, &tv1, &ev1.expire);getCurrTime(&now2);
tv2.tv_sec = 2;
timerAdd(&now2, &tv2, &ev2.expire);minHeapInsert(&timeHeap, &ev1);
minHeapInsert(&timeHeap, &ev2);while (1){计算需要睡眠的时间1、如果没有定时器,那么永远睡眠2、如果有定时器,计算还需要睡眠多久(小跟堆第一个节点减去当前时间),如果已经超期,则不睡眠epoll()  睡眠或者立马返回处理定时器1、获取当前时间nowstruct timerStruct ev;while ((ev = minHeapTop(&timeHeap))){if (TimerAfter(&ev->expire, now )){最小的都没超期直接返回}//处理超期minHeapRemove();先删除在调用定时器的回调函数}}

学习OO,实现的小跟堆代码相关推荐

  1. 深度学习大图切成小块图片代码---针对图像分割而言

    1 根据图片大小和patch大小生成切图位置: import glob import os.pathimport numpy as np from skimage import io as sio f ...

  2. Java堆排序(大顶堆小顶堆及应用实例)

    自己理解所得,如有错误欢迎随时指摘: 目录: 堆概念 堆结构 堆排序步骤 大顶堆代码.小顶堆代码 实际应用及实例代码 小顶堆删除图解代码.插入代码 小顶堆插入图解 时间复杂度分析 1.百度->概 ...

  3. c 语言掷骰子游戏,C 语言编程学习: 制作掷骰子小游戏

    C 语言编程学习: 制作掷骰子小游戏 问题描述 骰子是一个有六个面的正方体, 每个面分别印有 16 之间的小圆点代表点数. 假设这个游戏的规则是: 两个人轮流掷骰子 6 次, 并将每次投掷的点数累加起 ...

  4. 小顶堆数据结构C/C++代码实现

    相比队列和栈,很多人可能对堆的概念比较陌生,下面个给出堆的本质概念 一.堆也是一种数据结构,从实际应用意义来说,他是一种最优级别数据永远在第一位的队列,本文皆以最小值为例(小顶堆),即它变相是一种会永 ...

  5. 【LeetCode笔记】347. 前K个高频元素(Java、优先队列、小顶堆、HashMap)

    文章目录 题目描述 思路 & 代码 更新版:引入 stream 流 + Lambda 题目描述 时间复杂度小于O(n*logn),否则直接sort,再遍历就很轻松. 很有学习价值的题目,第一次 ...

  6. 堆排序:大顶堆和小顶堆 + 前K个高频元素

    堆 一.堆排序 小顶堆 举个栗子 大顶堆 二.前K个高频元素 思路分析 三.构造器代码解析 一.堆排序 要了解大顶堆和小顶堆,我们先简单了解一下堆排序. 堆排序(Heapsort)是指利用堆这种数据结 ...

  7. c语言标准模板小顶堆,堆排序(大顶堆、小顶堆)----C语言

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

  8. (补)算法训练Day13 | LeetCode150. 逆波兰表达式求值(栈应用);LeetCode239. 滑动窗口最大值(单调队列);LeetCode347. 前K个高频元素(小顶堆,优先级队列)

    目录 LeetCode150. 逆波兰表达式求值 1. 思路 2. 代码实现 3. 复杂度分析 4. 思考 LeetCode239. 滑动窗口最大值 1. 思路 2. 代码实现 3. 复杂度分析 4. ...

  9. 算法学习 (门徒计划)2-2 堆(Heap)与优先队列 学习笔记

    算法学习 (门徒计划)2-2 堆(Heap)与优先队列 学习笔记 前言 堆(Heap)的概念和基础操作 基础概念 基础操作 入堆与上滤 出堆与下滤 自定义类实现堆 优先队列 经典例题,堆的基础应用 l ...

  10. python软件代码示例-用Python写一个模拟qq聊天小程序的代码实例

    Python 超简单的聊天程序 客户端: import socket, sys host = '10.248.27.23' # host = raw_input("Plz imput des ...

最新文章

  1. 最新!2021中国内地大学ESI排名出炉:326所高校上榜!
  2. Stream Processing: Apache Kafka的Exactly-once的定义 原理和实现
  3. 《SQL Server 2012 T-SQL基础》读书笔记 - 1.背景
  4. 【Java Web前端开发】BootStrap入门
  5. Android 学习笔记四:创建工具栏按钮
  6. 力扣 数组中的第K个最大元素
  7. 如何在create-react-app中使用Workbox构建自定义PWA
  8. 借用 FCKEditor 的文件上传/管理界面
  9. 敏捷开发一千零一问系列之十五:同时实施CMMI和敏捷哪个为主?
  10. 计算机科学与技术参考论文题目关本科,优秀计算机本科论文题目推荐
  11. 用户输入错误验证码错误三次后,锁定该用户3分钟 redis 使用案列
  12. 服务器硬盘sas速度多少,R710服务器6块硬盘(SAS 300G 15000转)做完Raid5后读写速度没有一台普通台式机硬盘的读写速度快...
  13. cv岗工作做什么_成为一个CV之前都需要做一些什么准备工作?
  14. 消毒机器人市场前景分析
  15. Python程序员经常会遇到文件权限问题,例如在打开或写入文件时出现“PermissionError: [Errno 13] Permission denied...
  16. java实现简单控制台出租房屋管理系统
  17. Oracle数据库基本常用命令
  18. pygame图片精灵
  19. 300元搭建远程下载+视频服务器 Debian nginx+aria2+各种视频服务(smb+nfs+dlna)
  20. vue模板字符串中点击事件传递参数

热门文章

  1. Spring No mapping found for HTTP request with URI错误
  2. IIS连接oralce数据提示“System.Data.OracleClient 需要 Oracle 客户端软件 8.1.7 或更高版本”...
  3. Zen Cart 如何添加地址栏上的小图标
  4. sendEmail invalid SSL_version at SSL.pm
  5. CentOS6.7系统优化加强牢固脚本
  6. 在EF4.1的DBContext中实现事务处理(BeginTransaction)和直接执行SQL语句的示例
  7. JavaScript技巧写法
  8. LCS最长公共子序列——动态规划
  9. DBCP数据库连接失效的解决方法(Io 异常:Connection reset)
  10. oracle忘记sys密码处理