heap
堆是 swoole
实现定时器最重要的数据结构,定时器将各个定时任务按照其下一次执行的时间构建最小堆,快速进行插入与删除。
heap
数据结构heap
中 num
是现有数据堆的数量,size
是数据堆的大小,type
用于确定数据堆是最大堆还是最小堆,nodes
是数据堆的节点。swHeap_node
中 priority
是数据堆的权重,也是数据堆排序的依据,position
是其在数据堆中的位置。
typedef struct swHeap_node
{
uint64_t priority;
uint32_t position;
void *data;
} swHeap_node;
typedef struct _swHeap
{
uint32_t num;
uint32_t size;
uint8_t type;
swHeap_node **nodes;
} swHeap;
[
](http://owql68l6p.bkt.clouddn.com/WX20180911-211701@2x.png)
heap
数据堆swHeap_new
创建数据堆创建一个数据堆就是初始化 swHeap
的各个属性。
swHeap *swHeap_new(size_t n, uint8_t type)
{
swHeap *heap = sw_malloc(sizeof(swHeap));
if (!heap)
{
return NULL;
}
if (!(heap->nodes = sw_malloc((n + 1) * sizeof(void *))))
{
sw_free(heap);
return NULL;
}
heap->num = 1;
heap->size = (n + 1);
heap->type = type;
return heap;
}
swHeap_push
数据入堆数据入堆首先要检查 heap
的 size
是否已经足够,如果不够那么需要扩容。
swHeap_bubble_up
函数负责将数据节点提升到数据堆中相应的位置。方法很简单,新的数据节点不断的和父节点进行对比,符合条件就进行替换,不符合条件就停止,结束。
swHeap_node* swHeap_push(swHeap *heap, uint64_t priority, void *data)
{
void *tmp;
uint32_t i;
uint32_t newsize;
if (heap->num >= heap->size)
{
newsize = heap->size * 2;
if (!(tmp = sw_realloc(heap->nodes, sizeof(void *) * newsize)))
{
return NULL;
}
heap->nodes = tmp;
heap->size = newsize;
}
swHeap_node *node = sw_malloc(sizeof(swHeap_node));
if (!node)
{
return NULL;
}
node->priority = priority;
node->data = data;
i = heap->num++;
heap->nodes[i] = node;
swHeap_bubble_up(heap, i);
return node;
}
#define left(i) ((i) << 1)
#define right(i) (((i) << 1) + 1)
#define parent(i) ((i) >> 1)
static void swHeap_bubble_up(swHeap *heap, uint32_t i)
{
swHeap_node *moving_node = heap->nodes[i];
uint32_t parent_i;
for (parent_i = parent(i);
(i > 1) && swHeap_compare(heap->type, heap->nodes[parent_i]->priority, moving_node->priority);
i = parent_i, parent_i = parent(i))
{
heap->nodes[i] = heap->nodes[parent_i];
heap->nodes[i]->position = i;
}
heap->nodes[i] = moving_node;
moving_node->position = i;
}
static sw_inline int swHeap_compare(uint8_t type, uint64_t a, uint64_t b)
{
if (type == SW_MIN_HEAP)
{
return a > b;
}
else
{
return a < b;
}
}
swHeap_change_priority
改变数据的权重改变了数据节点的权重之后,需要重新进行堆排序,将数据节点向上提升,或者将数据向下调整。向下调整方法也很简单,不断的和两个子节点进行比较,调整该数据节点和子节点的顺序。
void swHeap_change_priority(swHeap *heap, uint64_t new_priority, void* ptr)
{
swHeap_node *node = ptr;
uint32_t pos = node->position;
uint64_t old_pri = node->priority;
node->priority = new_priority;
if (swHeap_compare(heap->type, old_pri, new_priority))
{
swHeap_bubble_up(heap, pos);
}
else
{
swHeap_percolate_down(heap, pos);
}
}
static void swHeap_percolate_down(swHeap *heap, uint32_t i)
{
uint32_t child_i;
swHeap_node *moving_node = heap->nodes[i];
while ((child_i = swHeap_maxchild(heap, i))
&& swHeap_compare(heap->type, moving_node->priority, heap->nodes[child_i]->priority))
{
heap->nodes[i] = heap->nodes[child_i];
heap->nodes[i]->position = i;
i = child_i;
}
heap->nodes[i] = moving_node;
moving_node->position = i;
}
static uint32_t swHeap_maxchild(swHeap *heap, uint32_t i)
{
uint32_t child_i = left(i);
if (child_i >= heap->num)
{
return 0;
}
swHeap_node * child_node = heap->nodes[child_i];
if ((child_i + 1) < heap->num && swHeap_compare(heap->type, child_node->priority, heap->nodes[child_i + 1]->priority))
{
child_i++;
}
return child_i;
}
swHeap_pop
弹出堆顶元素弹出堆顶元素后,需要重新调整整个数据堆。方法是将尾部元素和堆顶元素进行交换,然后再对堆顶元素进行排序。
void *swHeap_pop(swHeap *heap)
{
swHeap_node *head;
if (!heap || heap->num == 1)
{
return NULL;
}
head = heap->nodes[1];
heap->nodes[1] = heap->nodes[--heap->num];
swHeap_percolate_down(heap, 1);
void *data = head->data;
sw_free(head);
return data;
}
swHeap_remove
删除元素删除堆节点元素和弹出堆顶元素类似,都是先将该元素和尾部元素进行替换,然后再对其进行排序。由于尾部元素不一定比待删除的元素权重高,因此需要先判断其权重,再决定是提升还是降低。
int swHeap_remove(swHeap *heap, swHeap_node *node)
{
uint32_t pos = node->position;
heap->nodes[pos] = heap->nodes[--heap->num];
if (swHeap_compare(heap->type, node->priority, heap->nodes[pos]->priority))
{
swHeap_bubble_up(heap, pos);
}
else
{
swHeap_percolate_down(heap, pos);
}
return SW_OK;
}
Original url: Access
Created at: 2018-10-10 17:13:42
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论