libevent(二)尾队列 && 最小堆
本文主要研究libevent中用来存储事件的两个结构体。
尾队列
具体定义位于queue.h中。
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
} #define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
} #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) #define TAILQ_INIT(head) do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
} while () #define TAILQ_INSERT_TAIL(head, elm, field) do { \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
} while () #define TAILQ_INSERT_HEAD(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
} while () #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
} while () #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
} while () #define TAILQ_REMOVE(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
} while ()
从定义可以看出,尾队列是一个双向链表,具体表现为:
一个小DEMO:
#include <stdio.h>
#include <stdlib.h>
#include <sys/queue.h> #define LIST_SIZE 5 // 声明头结点
TAILQ_HEAD(event_list, event);
// 声明元素结点
struct event {
int value;
TAILQ_ENTRY(event) field;
}; int main(int argc, char **argv) {
event_list *list = (event_list*)malloc(sizeof(event_list));
TAILQ_INIT(list); event *item;
for (int i = ; i < LIST_SIZE; i++) {
item = (event*)malloc(sizeof(event));
item->value = i;
item->field.tqe_next = NULL;
item->field.tqe_prev = NULL; TAILQ_INSERT_TAIL(list, item, field);
} printf("当前list: ");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
printf("%d ", item->value);
}
printf("\n"); event **test = list->tqh_first->field.tqe_prev;
if (test == &list->tqh_first) {
printf("guess right\n");
} printf("尾部插入结点: 10\n");
item = (event*)malloc(sizeof(event));
item->value = ;
item->field.tqe_next = NULL;
item->field.tqe_prev = NULL;
TAILQ_INSERT_TAIL(list, item, field); printf("当前list: ");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
printf("%d ", item->value);
}
printf("\n"); printf("头部插入结点: 20\n");
item = (event*)malloc(sizeof(event));
item->value = ;
item->field.tqe_next = NULL;
item->field.tqe_prev = NULL;
TAILQ_INSERT_HEAD(list, item, field); printf("当前list: ");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
printf("%d ", item->value);
}
printf("\n"); printf("在值为3的结点之后插入结点: 30\n");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
if (item->value == ) {
event *new_item = (event*)malloc(sizeof(event));
new_item->value = ;
new_item->field.tqe_next = NULL;
new_item->field.tqe_prev = NULL;
TAILQ_INSERT_AFTER(list, item, new_item, field);
}
} printf("当前list: ");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
printf("%d ", item->value);
}
printf("\n"); printf("在值为1的结点之前插入结点: 40\n");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
if (item->value == ) {
event *new_item = (event*)malloc(sizeof(event));
new_item->value = ;
new_item->field.tqe_next = NULL;
new_item->field.tqe_prev = NULL;
TAILQ_INSERT_BEFORE(item, new_item, field);
}
} printf("当前list: ");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
printf("%d ", item->value);
}
printf("\n"); printf("删除值为3的结点\n");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
if (item->value == ) {
TAILQ_REMOVE(list, item, field);
}
} printf("当前list: ");
for (item = list->tqh_first; item; item = item->field.tqe_next) {
printf("%d ", item->value);
}
printf("\n"); printf("Done\n");
}
最小堆
typedef struct min_heap
{
struct event** p; // 指向event*指针数组
unsigned n, a; // a表示堆的大小,n表示堆中元素个数
} min_heap_t;
void min_heap_ctor(min_heap_t* s) { s->p = ; s->n = ; s->a = ; }
void min_heap_elem_init(struct event* e) { e->ev_timeout_pos.min_heap_idx = -; }
unsigned min_heap_size(min_heap_t* s) { return s->n; }
参考资料:
do {...} while (0) 的用途汇总(欢迎补充)
libevent(二)尾队列 && 最小堆的更多相关文章
- libevent中最小堆实现算法解析
libevent,一个非常好的c的网络库,最近开始学习并分析下,做个记录.源码选用的1.4版本.因为感觉这版的代码比较精简,也没有太多宏定义,个人感觉适合学习原理. 从哪里开始呢,我选择从一些最简单的 ...
- Libevent源码分析(一):最小堆
Libevent中的timeout事件是使用最小堆来管理维护的.代码位于<minheap-internal.h>. 看函数命名和代码风格应该是一个C++程序员,函数名都挺好懂的,只是下面这 ...
- ZOJ 2724 Windows Message Queue (优先级队列,水题,自己动手写了个最小堆)
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm& ...
- java实现最小堆
1.堆:通常通过二叉堆,实为二叉树的一种,分为最小堆和最大堆,具有以下性质: 任意节点小于它的所有后裔,最小元在堆的根上. 堆总是一棵完全树 将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小 ...
- 优先队列——二项队列(binominal queue)
[0]README 0.1) 本文文字描述部分转自 数据结构与算法分析, 旨在理解 优先队列——二项队列(binominal queue) 的基础知识: 0.2) 本文核心的剖析思路均为原创(inse ...
- Python3实现最小堆建堆算法
今天看Python CookBook中关于“求list中最大(最小)的N个元素”的内容,介绍了直接使用python的heapq模块的nlargest和nsmallest函数的解决方式,记得学习数据结构 ...
- 【数据结构】通用的最小堆(最大堆)D-ary Heap
听说有一种最小(大)堆,不限于是完全二叉树,而是完全D叉树,名为D-ary Heap(http://en.wikipedia.org/wiki/D-ary_heap).D可以是1,2,3,4,100, ...
- My集合框架第五弹 最小堆
二叉堆(以最小堆为例),其具有结构性质和堆序性质结构性质: 堆是一棵完全的二叉树,一颗高为h的完全二叉树有2^h到2^h-1个节点,高度为log N 而且该结构可以很容易的使用数 ...
- 最小堆实现优先队列:Python实现
最小堆实现优先队列:Python实现 堆是一种数据结构,因为Heapsort而被提出.除了堆排序,“堆”这种数据结构还可以用于优先队列的实现. 堆首先是一个完全二叉树:它除了最底层之外,树的每一层的都 ...
随机推荐
- python--->相对和绝对路径
绝对路径(absolute path):从根开始找 eg:c:\file\01.txt 相对路径(relative path):相对当前文件内找 ../ # 当前文件的上一级 os.path ...
- coding++:漫画版-了解什么是分布式事务?
————— 第二天 ————— ———————————— 假如没有分布式事务: 在一系列微服务系统当中,假如不存在分布式事务,会发生什么呢?让我们以互联网中常用的交易业务为例子: 上图中包含了库存 ...
- Mac配置hosts文件
说明:工作里面有时候会遇到内网办公的环境,需要对使用的IP和地址进行配置到hosts文件内,所以记录一下: 1,Windows配置hosts Windows里面直接打开文件夹,可进行找到system/ ...
- SQL数据类型:nchar,char,varchar,nvarchar 的区别和应用场景
概括: char:固定长度,存储ANSI字符,不足的补英文半角空格.CHAR存储定长数据很方便,CHAR字段上的索引效率级高,比如定义CHAR(10),那么不论你存储的数据是否达到了10个字节,都要占 ...
- sql 自增序列
一.使用set identity_insert [database][owner][table]on设置时,要在插入语句中显示列出插入的列;
- Python 分析后告诉你闲鱼上哪些商品抢手?
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:[Airpython] PS:如有需要Python学习资料的小伙伴可以 ...
- cucumber学习索引
Cucumber(1) —— 环境配置 Cucumber(2)——目录结构以及基本语法 Cucumber(3)——命令以及日志 Cucumber(4)——jenkins的集成
- PHP函数:fopen
fopen() - 打开文件或者 URL. 注意:array_key_exists() 仅仅搜索第一维的键. 多维数组里嵌套的键不会被搜索到. 说明: fopen ( string $filenam ...
- powershell提示无法将“”项识别
解决: 完成! 解释: 权限问题.Powershell脚本的4种执行权限介绍,Windows默认不允许任何脚本运行,我们可以使用"Set-ExecutionPolicy"cmdle ...
- [Abp vNext 入坑分享] - 3.简单的用户模块功能开发
一.简要说明 本篇文章开始进行业务模块的开发模拟,借助user模块来进行业务开发,主要是用户相关的基础操作.主要是先使用Users来体验整个开发的流程.主要是先把一个基础流程跑顺利,在这里我并不会过于 ...