使用跳表实现定时器

26 篇文章 0 订阅
19 篇文章 0 订阅

使用跳表实现定时器

  • 使用的是redis中使用的跳表结构,直接从中迁移出来并修改。
  • 通过跳表实现的时间轮,查询第一个数据的时间复杂度就是O(1),插入时间复杂度就 大概率的趋向于O(logn(N))。
  • 定时器本身就是从头部开始取数据,跳表这一数据结构就特别匹配定时器的实现。

文件skiplist.h

#ifndef _MARK_SKIPLIST_
#define _MARK_SKIPLIST_

/* ZSETs use a specialized version of Skiplists */
#define ZSKIPLIST_MAXLEVEL 32 /* Should be enough for 2^64 elements */
#define ZSKIPLIST_P 0.25      /* Skiplist P = 1/4 */

typedef struct zskiplistNode zskiplistNode;
typedef void (*handler_pt) (zskiplistNode *node);
struct zskiplistNode {
    // sds ele;
    // double score;
    unsigned long score; // 时间戳
    handler_pt handler;
    /* struct zskiplistNode *backward; 从后向前遍历时使用*/
    struct zskiplistLevel {
        struct zskiplistNode *forward;
        /* unsigned long span; 这个存储的level间节点的个数,在定时器中并不需要*/ 
    } level[];
};

typedef struct zskiplist {
    // 添加一个free的函数
    struct zskiplistNode *header/*, *tail 并不需要知道最后一个节点*/;
    int length;
    int level;
} zskiplist;

zskiplist *zslCreate(void);
void zslFree(zskiplist *zsl);
zskiplistNode *zslInsert(zskiplist *zsl, unsigned long score, handler_pt func);
zskiplistNode* zslMin(zskiplist *zsl);
void zslDeleteHead(zskiplist *zsl);
void zslDelete(zskiplist *zsl, zskiplistNode* zn); 

void zslPrint(zskiplist *zsl);
#endif

文件skiplist.c

#include <stdlib.h>
#include <stdio.h>
#include "skiplist.h"

void defaultHandler(zskiplistNode *node) {
}

/* Create a skiplist node with the specified number of levels. */
zskiplistNode *zslCreateNode(int level, unsigned long score, handler_pt func) {
    zskiplistNode *zn =
        malloc(sizeof(*zn)+level*sizeof(struct zskiplistLevel));
    zn->score = score;
    zn->handler = func;
    return zn;
}


// 创建跳表
zskiplist *zslCreate(void) {
    int j;
    zskiplist *zsl;

    zsl = malloc(sizeof(*zsl));
    zsl->level = 1;
    zsl->length = 0;
    zsl->header = zslCreateNode(ZSKIPLIST_MAXLEVEL,0,defaultHandler);
    for (j = 0; j < ZSKIPLIST_MAXLEVEL; j++) {
        zsl->header->level[j].forward = NULL;
    }
    return zsl;
}

/* Free a whole skiplist. */
void zslFree(zskiplist *zsl) {
    zskiplistNode *node = zsl->header->level[0].forward, *next;

    free(zsl->header);
    while(node) {
        next = node->level[0].forward;
        free(node);
        node = next;
    }
    free(zsl);
}

// 获取随机的层数
int zslRandomLevel(void) {
    int level = 1;
    while ((arc4random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
        level += 1;
    return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}

// 向跳表插入节点
zskiplistNode *zslInsert(zskiplist *zsl, unsigned long score, handler_pt fun){
    zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
    int i, level;

    x = zsl->header;
	// update记录路径,方便建立节点时候的的前指针指向他
    for (i = zsl->level-1; i >= 0; i--) {
        while (x->level[i].forward &&
                x->level[i].forward->score < score)
        {
            x = x->level[i].forward;
        }
        update[i] = x;
    }
    level = zslRandomLevel();
    printf("zskiplist add node level = %d\n", level);
	// 高度超过了原先最大高度,补充头指向新建的路径
    if (level > zsl->level) {
        for (i = zsl->level; i < level; i++) {
            update[i] = zsl->header;
        }
        zsl->level = level;
    }
    x = zslCreateNode(level,score,func);
    for (i = 0; i < level; i++) {
		// 新建节点接续他的前节点的后续指针
        x->level[i].forward = update[i]->level[i].forward;
		// 前指针指向新建节点
        update[i]->level[i].forward = x;
    }

    zsl->length++;
    return x;
}

// 头结点不存数据,头结点的第一个后续节点为最小
zskiplistNode* zslMin(zskiplist *zsl) {
    zskiplistNode *x;
    x = zsl->header;
    return x->level[0].forward;
}

// 删除跳表头部节点
void zslDeleteHead(zskiplist *zsl) {
    zskiplistNode *update[ZSKIPLIST_MAXLEVEL];
    zskiplistNode *x = zslMin(zsl);
    if (!x) return;
    int i;
    for (i = zsl->level-1; i >= 0; i--) {
		// 拷贝x的每一层的后续节点
        if (zsl->header->level[i].forward == x) {
            zsl->header->level[i].forward = x->level[i].forward;
        }
    }
	// 计算跳表的最高层
    while(zsl->level > 1 && zsl->header->level[zsl->level-1].forward == NULL)
        zsl->level--;
    zsl->length--;
}


void zslDeleteNode(zskiplist *zsl, zskiplistNode *x, zskiplistNode **update) {
    int i;
	// 将行走路径上原先指向x的节点指向x的后续节点
    for (i = 0; i < zsl->level; i++) {
        if (update[i]->level[i].forward == x) {
            update[i]->level[i].forward = x->level[i].forward;
        } 
    }
    while(zsl->level > 1 && zsl->header->level[zsl->level-1].forward == NULL)
        zsl->level--;
    zsl->length--;
}

// 删除任一跳表节点
void zslDelete(zskiplist *zsl, zskiplistNode* zn) {
    zskiplistNode *update[ZSKIPLIST_MAXLEVEL], *x;
    int i;

    x = zsl->header;
	// update存储行走路径
    for (i = zsl->level-1; i >= 0; i--) {
        while (x->level[i].forward &&
                x->level[i].forward->score < zn->score)
        {
            x = x->level[i].forward;
        }
        update[i] = x;
    }
	// 此时循环刚出来的是欲删除节点的前序节点
    x = x->level[0].forward;
    if (x && zn->score == x->score) {
        zslDeleteNode(zsl, x, update);
        free(x);
    }
}

void zslPrint(zskiplist *zsl) {
    zskiplistNode *x;
    x = zsl->header;
    x = x->level[0].forward;
    printf("start print skiplist level = %d\n", zsl->level);
    int i;
    for (i = 0; i < zsl->length; i++) {
        printf("skiplist ele %d: score = %lu\n", i+1, x->score);
        x = x->level[0].forward;
    }
}

定时器实现

#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
#if defined(__APPLE__)
#include <AvailabilityMacros.h>
#include <sys/time.h>
#include <mach/task.h>
#include <mach/mach.h>
#endif
#include "skiplist.h"

static uint32_t
current_time() {
	uint32_t t;
#if !defined(__APPLE__) || defined(AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER)
	struct timespec ti;
	clock_gettime(CLOCK_MONOTONIC, &ti);
	t = (uint32_t)ti.tv_sec * 1000;
	t += ti.tv_nsec / 1000000;
#else
	struct timeval tv;
	gettimeofday(&tv, NULL);
	t = (uint32_t)tv.tv_sec * 1000;
	t += tv.tv_usec / 1000;
#endif
	return t;
}

zskiplist *init_timer() {
    return zslCreate();
}

zskiplistNode *add_timer(zskiplist *zsl, uint32_t msec, handler_pt func) {
    msec += current_time();
    printf("add_timer expire at msec = %u\n", msec);
    return zslInsert(zsl, msec, func);
}

void del_timer(zskiplist *zsl, zskiplistNode *zn) {
    zslDelete(zsl, zn);
}

void expire_timer(zskiplist *zsl) {
    zskiplistNode *x;
    uint32_t now = current_time();
    for (;;) {
        x = zslMin(zsl);
        if (!x) break;
        if (x->score > now) break;
        printf("touch timer expire time=%lu, now = %u\n", x->score, now);
        x->handler(x);
        zslDeleteHead(zsl);
    }
}

void print_hello(zskiplistNode *zn) {
    printf("hello world time = %lu\n", zn->score);
}

int main()
{
    zskiplist *zsl = init_timer();
    add_timer(zsl, 3010, print_hello);
    add_timer(zsl, 3004, print_hello);
    zskiplistNode *zn = add_timer(zsl, 3005, print_hello);
    del_timer(zsl, zn);
    add_timer(zsl, 3008, print_hello);
    add_timer(zsl, 3003, print_hello);
    // zslPrint(zsl);
    for (;;) {
        expire_timer(zsl);
        usleep(10000); // 暂用睡眠函数替代阻塞
    }
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 跳表是一种高效的数据结构,它结合了链表和二分查找的优点,可以在log(n)的时间复杂度内完成查询、插入和删除操作。 使用 Python 实现跳表可以通过自定义一个类,实现跳表的相关操作。这个类需要有插入、删除、查询等方法,还需要维护跳表中各个节点的关系。 示例代码: ``` class Node: def __init__(self, key, value, level): self.key = key self.value = value self.forward = [None] * (level + 1) class SkipList: def __init__(self, max_level, p): self.MAX_LEVEL = max_level self.p = p self.header = self.createNode(self.MAX_LEVEL, -1, -1) self.level = 0 def createNode(self, level, key, value): n = Node(key, value, level) return n def randomLevel(self): level = 0 while random.random() < self.p and level < self.MAX_LEVEL: level += 1 return level def insert(self, key, value): update = [None] * (self.MAX_LEVEL + 1) x = self.header for i in range(self.level, -1, -1): while x.forward[i] and x.forward[i].key < key: x = x.forward[i] update[i] = x x = x.forward[0] if x is None or x.key != key: rlevel = self.randomLevel() if rlevel > self.level: for i in range(self.level + 1, rlevel + 1): update[i] = self.header self.level = rlevel x = self.createNode(rlevel, key, value) for i in range(rlevel + 1): x.forward[i] = update[i].forward[i] update[i].forward[i] = x def delete(self, key): update = [None] * (self.MAX_LEVEL + 1) x = self.header for i in range(self.level, -1, -1): while x.forward[i] and x.forward[i].key < key: x = x. ### 回答2: 跳表(Skip List)是一种用于有序链表数据结构,它允许快速的搜索、插入和删除操作。在跳表中,每个节点都有多个指针,指向其他节点,从而形成多层次的链表结构。每一层都是前一层的子集,跳跃指针允许我们快速地定位到需要搜索的节点。 使用Python实现跳表可以按照以下步骤进行: 1. 定义SkipNode类:这个类表示跳表中的每个节点,每个节点包含一个值和多个指针。可以使用Python的类和对象来表示节点。 2. 定义SkipList类:这个类表示整个跳表。它包含一个指向跳表头部的指针和其他辅助方法,如插入、搜索和删除等操作。 3. 实现插入操作:插入操作需要保持跳表的有序性,可以从最高层开始,根据节点的值和搜索路径将节点插入到相应的位置。 4. 实现搜索操作:搜索操作需要根据节点的值和搜索路径找到目标节点,可以从最高层开始,通过比较节点的值和目标值来确定前进方向。 5. 实现删除操作:删除操作需要将目标节点从跳表中删除,可以根据节点的值和搜索路径找到目标节点,并更新指针来跳过目标节点。 通过上述步骤,可以使用Python实现跳表数据结构。 ### 回答3: 跳表(Skip List)是一种有序数据结构,它使用了多层链表来加速查询操作。在跳表中,每个节点除了保存自身的值外,还保存了若干个指向其他节点的引用,这些引用就像是跳过了中间的节点,直接连接到了更远的节点,从而实现了快速的查找。 要使用Python实现跳表,可以定义一个节点类,节点类包含节点的值以及一个指向下一个节点的指针。然后可以定义一个跳表类,跳表类包含了跳表的头节点以及其他相关方法和属性。 下面是一个简单的Python代码实现跳表的示例: ```python import random import math class SkipListNode: def __init__(self, value): self.value = value self.next = None self.down = None class SkipList: def __init__(self): self.head = None self.max_levels = 16 self.current_levels = 0 def flip_coin(self): return random.randint(0, 1) == 1 def insert(self, value): if self.head is None: self.head = SkipListNode(value) self.current_levels = 1 return level = 1 while self.flip_coin() and level < self.max_levels: level += 1 if level > self.current_levels: for _ in range(level - self.current_levels): new_head = SkipListNode(None) new_head.down = self.head self.head = new_head self.current_levels = level current = self.head prev = None while current: if current.value is None or current.value > value: if prev is None: prev = SkipListNode(value) prev.next = current self.head = prev else: new_node = SkipListNode(value) new_node.next = current prev.next = new_node prev.down = new_node prev = new_node prev = current current = current.next def search(self, value): current = self.head while current: if current.value == value: return True elif current.next and current.next.value <= value: current = current.next else: current = current.down return False def display(self): current = self.head while current: print(current.value, end=" -> ") current = current.next print("None") skip_list = SkipList() for i in range(1, 20): skip_list.insert(i) skip_list.display() print(skip_list.search(10)) print(skip_list.search(20)) ``` 上述代码是一个基本实现跳表的示例,通过`insert`方法可以将值插入跳表中,通过`search`方法可以查找值是否存在于跳表中。`display`方法用于打印跳表的内容。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值