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而被提出.除了堆排序,“堆”这种数据结构还可以用于优先队列的实现. 堆首先是一个完全二叉树:它除了最底层之外,树的每一层的都 ...
随机推荐
- python3 进程间通信之socket.socketpair()
python3 进程间通信之socket.socketpair() socket.socketpair()是什么鬼东西? socket.socketpair()函数仅返回两个已经连接的套接字对象,参数 ...
- 让图片适合在静态文本控件窗口大小 MFC
1.加入 IDC_STATIC1 静态文本控件. 2.为文本控件添加 STATIC 型变量 3.在OnInitDialog函数中添加以下代码 //设置该静态控件为显示位图的 m_bitmap.Modi ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(四)之Operators
At the lowest level, data in Java is manipulated using operators Using Java Operators An operator ta ...
- Daily Scrum 12/18/2015
Process: Zhaoyang: Some IOS UI upgrade to increase the users' experience. Minlong: Build a restful s ...
- Cobalt Strike系列教程第六章:安装扩展
Cobalt Strike系列教程分享如约而至,新关注的小伙伴可以先回顾一下前面的内容: Cobalt Strike系列教程第一章:简介与安装 Cobalt Strike系列教程第二章:Beacon详 ...
- Java核心技术--接口与内部类
接口implement 继承接口,即履行"义务". 接口中所有的方法自动属于public,在接口声明中,不必提供关键字public 接口中决不能含有实例域,也不能在接口中实现方法 ...
- vue axios post请求下载文件,后台springmvc完整代码
注意请求时要设置responseType,不加会中文乱码,被这个坑困扰了大半天... axios post请求: download(index,row){ var ts = ...
- DeepinV20系统文件管理器右键发送至为知笔记
1. 创作背景 昨天在深度系统上做了一个打开文件管理器选择文件右键发送文本至博客园的插件. 这个插件对于我自己来说是及其方便的东西,平时的学习积累,工作经验或者生活感悟,随手记下之后,就能够轻松发送出 ...
- TensorFlow keras 迁移学习
数据的读取 import tensorflow as tf from tensorflow.python import keras from tensorflow.python.keras.prepr ...
- Java IO 流-- 文件拷贝
IO流操作套路: 1.创建源: 2.选择流: 3.操作: 4.释放资源 上代码: package com.xzlf.io; import java.io.File; import java.io.Fi ...