本文主要研究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. js及jquery常用插件

    1.backstretch背景图片插件 可实现背景自适应效果 <script src="dist/js/lib/backstretch/jquery.backstretch.min.j ...

  2. 04 jmeter使用方式3种

    1.手工添加配置元件编写 2.jmeter+badboy 工具录制---不建议使用 3.设置代理服务器(jmeter添加‘非测试元件-http代理服务器’,再添加一个线程组用来保留代理抓取的url,设 ...

  3. while和do-while

    1. While(条件表达式){ 只要条件表达式结果为true,循环一直执行,当条件表达式结果为false的时候,循环终止 } 2. Do{ 循环体代码:首先执行该循环体代码一次.如果while后边的 ...

  4. util.Date与sql.Date的异同以及相互转换

    Java中有两个Date类 一个是java.util.Date通常情况下用它获取当前时间或构造时间 另一个是java.sql.Date是针对SQL语句使用的,它只包含日期而没有时间部分 两个类型的时间 ...

  5. Daily Scrum 1/11/2016

    Zhaoyang & Minlong: Took and edited the video which introduced our APP. Yandong: Summarized bugs ...

  6. Personal Photo Experience Proposal

      Background:             Our smart phones are the most widely-used cameras now, more and more photo ...

  7. java中如何理解:其他类型 + string 与 自增类型转换和赋值类型转换

    java中如何理解:其他类型 + string 与 自增类型转换和赋值类型转换 一.字符串与其他类型连接 public class DemoString{ public static void mai ...

  8. 9.回文数-LeetCode

    判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 示例 1: 输入: 121输出: true示例 2: 输入: -121输出: false解释: 从左向右读, ...

  9. 转:Cookies 和 Session的区别

    转自:http://blog.csdn.net/axin66ok/article/details/6175522 1.cookie 是一种发送到客户浏览器的文本串句柄,并保存在客户机硬盘上,可以用来在 ...

  10. HTTPie:替代 Curl 和 Wget 的现代 HTTP 命令行客户端

    HTTPie 工具是现代的 HTTP 命令行客户端,它能通过命令行界面与 Web 服务进行交互. -- Magesh Maruthamuthu 大多数时间我们会使用 curl 命令或是 wget 命令 ...