本文主要研究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(二)尾队列 && 最小堆的更多相关文章

  1. libevent中最小堆实现算法解析

    libevent,一个非常好的c的网络库,最近开始学习并分析下,做个记录.源码选用的1.4版本.因为感觉这版的代码比较精简,也没有太多宏定义,个人感觉适合学习原理. 从哪里开始呢,我选择从一些最简单的 ...

  2. Libevent源码分析(一):最小堆

    Libevent中的timeout事件是使用最小堆来管理维护的.代码位于<minheap-internal.h>. 看函数命名和代码风格应该是一个C++程序员,函数名都挺好懂的,只是下面这 ...

  3. ZOJ 2724 Windows Message Queue (优先级队列,水题,自己动手写了个最小堆)

    #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm& ...

  4. java实现最小堆

    1.堆:通常通过二叉堆,实为二叉树的一种,分为最小堆和最大堆,具有以下性质: 任意节点小于它的所有后裔,最小元在堆的根上. 堆总是一棵完全树 将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小 ...

  5. 优先队列——二项队列(binominal queue)

    [0]README 0.1) 本文文字描述部分转自 数据结构与算法分析, 旨在理解 优先队列——二项队列(binominal queue) 的基础知识: 0.2) 本文核心的剖析思路均为原创(inse ...

  6. Python3实现最小堆建堆算法

    今天看Python CookBook中关于“求list中最大(最小)的N个元素”的内容,介绍了直接使用python的heapq模块的nlargest和nsmallest函数的解决方式,记得学习数据结构 ...

  7. 【数据结构】通用的最小堆(最大堆)D-ary Heap

    听说有一种最小(大)堆,不限于是完全二叉树,而是完全D叉树,名为D-ary Heap(http://en.wikipedia.org/wiki/D-ary_heap).D可以是1,2,3,4,100, ...

  8. My集合框架第五弹 最小堆

    二叉堆(以最小堆为例),其具有结构性质和堆序性质结构性质: 堆是一棵完全的二叉树,一颗高为h的完全二叉树有2^h到2^h-1个节点,高度为log N            而且该结构可以很容易的使用数 ...

  9. 最小堆实现优先队列:Python实现

    最小堆实现优先队列:Python实现 堆是一种数据结构,因为Heapsort而被提出.除了堆排序,“堆”这种数据结构还可以用于优先队列的实现. 堆首先是一个完全二叉树:它除了最底层之外,树的每一层的都 ...

随机推荐

  1. std::lock_guard和std::unique_lock的区别

    std::lock_guard 1 初始化的时候锁定std::mutex std::mutex m_mtx; std::lock_guard<std::mutex> m_lock(m_mt ...

  2. iOS技能 - 最新美团、百度、腾讯、头条、阿里 面试题目记录

    关于面试题,可能没那么多时间来总结答案,有什么需要讨论的地方欢迎大家指教.主要记录一下准备过程,和面试的一些总结,希望能帮助到正在面试或者将要面试的同学吧. 美团 一面 1.简历上写的项目问了一遍,然 ...

  3. 【课程学习】课程2:十行代码高效完成深度学习POC

    本文用户记录黄埔学院学习的心得,并补充一些内容. 课程2:十行代码高效完成深度学习POC,主讲人为百度深度学习技术平台部:陈泽裕老师. 因为我是CV方向的,所以内容会往CV方向调整一下,有所筛检. 课 ...

  4. AJ学IOS(12)UI之UITableView学习(上)LOL英雄联盟练习

    AJ分享,必须精品 先看效果图 源代码 NYViewController的代码 #import "NYViewController.h" #import "NYHero. ...

  5. android29之UI控件的抽屉式实现方法之一(DrawerLayout和NavigationView)

    添加依赖 implementation 'com.google.android.material:material:1.2.0-alpha06' 在Layout中创建两个Xml布局文件,header. ...

  6. ******Prometheus(二)***********

    Prometheus的数据与安全模型: (1)Metric (度量)名字就是描述采集数据的名称——例如,website_visits_total 作为网站访问总数.名称可以包含ASCII字母.数字.下 ...

  7. 使用mysqlbinlog查看二进制日志

    (一)mysqlbinlog工具介绍 binlog类型是二进制的,也就意味着我们没法直接打开看,MySQL提供了mysqlbinlog来查看二进制日志,该工具类似于Oracle的logminer.my ...

  8. Java中的二分查找

    二分查找:(折半查找) 前提:数组必须是有序的. 思想:每次都猜中间的那个元素,比较大或者小,就能减少一半的元素.思路:A:定义最小索引,最大索引. B:比较出中间索引 C:拿中间索引的值和要查找的元 ...

  9. search(7)- elastic4s-search-filter模式

    现在我们可以开始探讨ES的核心环节:搜索search了.search又分filter,query两种模式.filter模式即筛选模式:将符合筛选条件的记录作为结果找出来.query模式则分两个步骤:先 ...

  10. 2019-2020-1 20199308《Linux内核原理与分析》第一周作业

    Linux 基础入门(新版)学习笔记 实验二 基本概念及操作 重要快捷键 Tab 补全命令 Ctrl+c 强行终止当前命令 历史命令 方向上键↑,恢复之前输入过的命令 通配符 在命令行中获取帮助 某个 ...