首页 > 其他分享 >定时器实现之红黑树(二)

定时器实现之红黑树(二)

时间:2024-12-08 14:33:19浏览次数:9  
标签:黑树 之红 定时器 node temp parent color rbtree left

1.概述

        书接上回定时器实现之最小堆(一),今天采用红黑树来作为定时器的容器,组织定时器的定时节点。

2.为什么红黑树能用来实现定时器

         前面一章提到过,能用来实现定时器的容器的基本要求就是有序,而红黑树的中序遍历就是有序的,如下图:

        并且,对于红黑树中最小和最大的节点分别位于最左和最右子树,基于这一现象,我们在定时器的实现中,对于找最近要过期的任务,只需要最左子树的叶子节点就行,这是我们高效判定定时任务是否触发的核心。

3.代码实现 

        对于红黑树用于定时器的实现参考了nginx 并增加了一些自己的东西具体如下:

//rbtree.h
#pragma once

struct rbtree_node {
    unsigned long long key;
    rbtree_node*       left;
    rbtree_node*       right;
    rbtree_node*       parent;
    unsigned char      color; // 0: red, 1: black
};

struct rbtree {
    rbtree_node* root;
    rbtree_node* sentinel; //哨兵节点
};

void rbtree_init(rbtree* r, rbtree_node* s);

void rbtree_insert(rbtree *tree, rbtree_node *node);

void rbtree_delete(rbtree *tree, rbtree_node *node);

rbtree_node* rbtree_min(rbtree *tree);

rbtree_node* rbtree_max(rbtree *tree);
//rbtree.cpp

#include "rbtree.h"


static void insert(rbtree_node* r, rbtree_node* n, rbtree_node* s) {
    rbtree_node  **p = nullptr;

    for ( ;; ) {
        p = (n->key < r->key) ? &r->left : &r->right;

        if (*p == s) {
            break;
        }

        r = *p;
    }

    *p = n;
    n->parent = r;
    n->left = s;
    n->right = s;
    n->color = 1;
}

static void rbtree_left_rotate(rbtree_node**r, rbtree_node* s, rbtree_node* n) {
    rbtree_node* temp = n->right;
    n->right = n->right->left;

    if(temp->left != s) {
        temp->left->parent = n;
    }

    temp->parent = n->parent;

    if(n == *r) {
        *r = temp;
    } else if(n == n->parent->left) {
        n->parent->left = temp;
    } else {
        n->parent->right = temp;
    }

    temp->left = n;
    n->parent = temp;
}

static void rbtree_right_rotate(rbtree_node**r, rbtree_node* s, rbtree_node* n) {
    rbtree_node  *temp;

    temp = n->left;
    n->left = temp->right;

    if (temp->right != s) {
        temp->right->parent = n;
    }

    temp->parent = n->parent;

    if (n == *r) {
        *r = temp;

    } else if (n == n->parent->right) {
        n->parent->right = temp;

    } else {
        n->parent->left = temp;
    }

    temp->right = n;
    n->parent = temp;
}

static rbtree_node* rbtree_min(rbtree_node* n, rbtree_node* s) {
    if(!n) {
        return nullptr;
    }

    while(n->left != s) {
        n = n->left;
    }

    return n;
}

static rbtree_node* rbtree_max(rbtree_node* n, rbtree_node* s) {
    if(!n) {
        return nullptr;
    }

    while(n->right != s) {
        n = n->right;
    }

    return n;
}

void rbtree_init(rbtree* r, rbtree_node* s) {
    s->color = 0;
    r->root = s;
    r->sentinel = s;
}

void rbtree_insert(rbtree *tree, rbtree_node *node) {
    rbtree_node** root = &tree->root;
    rbtree_node* sentinel = tree->sentinel;

    if(*root == sentinel) {
        node->parent = nullptr;
        node->left = sentinel;
        node->right = sentinel;
        node->color = 0;
        *root = node;
        return;
    }

    // 插入节点
    insert(*root, node, sentinel);

    rbtree_node* temp = nullptr;
    //判断是否需要调整使其平衡
    while(node != *root && node->parent->color) {
        if(node->parent == node->parent->parent->left) {
            temp = node->parent->parent->right;
            //如果叔父节点是红色则直接变色并进入下一轮调整
            if(temp->color) {
                node->parent->color = 0;
                temp->color = 0;
                node->parent->parent->color = 1;
                node = node->parent->parent;
            } else {
                //如果当前插入节点是父节点的左节点先对父节点进行左旋    
                if(node == node->parent->right) {
                    node = node->parent;
                    rbtree_left_rotate(root, sentinel, node);
                }

                node->parent->color = 0;
                node->parent->parent->color = 1;
                rbtree_right_rotate(root, sentinel, node->parent->parent);
            }
        } else {
            temp = node->parent->parent->left;
            //如果叔父节点是红色则直接变色并进入下一轮调整
            if(temp->color) {
                node->parent->color = 0;
                temp->color = 0;
                node->parent->parent->color = 1;
                node = node->parent->parent;
            } else {
                //如果当前插入节点是父节点的左节点先对父节点进行右旋
                if(node == node->parent->left) {
                    node = node->parent;
                    rbtree_right_rotate(root, sentinel, node);
                }

                node->parent->color = 0;
                node->parent->parent->color = 1;
                rbtree_left_rotate(root, sentinel, node->parent->parent);
            }
        }
    }

    (*root)->color = 0;
}

void rbtree_delete(rbtree *tree, rbtree_node *node) {
    rbtree_node** root = &tree->root;
    rbtree_node* sentinel = tree->sentinel;
    rbtree_node* subst = nullptr;
    rbtree_node* temp = nullptr;

    if (node->left == sentinel) {
        temp = node->right;
        subst = node;

    } else if (node->right == sentinel) {
        temp = node->left;
        subst = node;
    } else {
        subst = rbtree_min(node->right, sentinel);
        if (subst->left != sentinel) {
            temp = subst->left;
        } else {
            temp = subst->right;
        }
    }

    if (subst == *root) {
        *root = temp;
        temp->color = 0;
        return;
    }

    if (subst == subst->parent->left) {
        subst->parent->left = temp;
    } else {
        subst->parent->right = temp;
    }

    if (subst == node) {
        temp->parent = subst->parent;
    } else {
        if (subst->parent == node) {
            temp->parent = subst;

        } else {
            temp->parent = subst->parent;
        }

        subst->left = node->left;
        subst->right = node->right;
        subst->parent = node->parent;
        subst->color = node->color;

        if (node == *root) {
            *root = subst;
        } else {
            if (node == node->parent->left) {
                node->parent->left = subst;
            } else {
                node->parent->right = subst;
            }
        }

        if (subst->left != sentinel) {
            subst->left->parent = subst;
        }

        if (subst->right != sentinel) {
            subst->right->parent = subst;
        }
    }

    if (subst->color) {
        return;
    }

    rbtree_node* w = nullptr;
    while (temp != *root && !temp->color) {

        if (temp == temp->parent->left) {
            w = temp->parent->right;

            if (w->color) {
                w->color = 1;
                temp->parent->color = 0;
                rbtree_left_rotate(root, sentinel, temp->parent);
                w = temp->parent->right;
            }

            if (!w->left->color && !w->right->color) {
                w->color = 0;
                temp = temp->parent;

            } else {
                if (!w->right->color) {
                    w->left->color = 0;
                    w->color = 1;
                    rbtree_right_rotate(root, sentinel, w);
                    w = temp->parent->right;
                }

                w->color = temp->color;
                temp->parent->color = 0;
                w->right->color = 0;
                rbtree_left_rotate(root, sentinel, temp->parent);
                temp = *root;
            }

        } else {
            w = temp->parent->left;

            if (w->color) {
                w->color = 0;
                temp->parent->color = 1;
                rbtree_right_rotate(root, sentinel, temp->parent);
                w = temp->parent->left;
            }

            if (!w->left->color && !w->right->color) {
                w->color = 1;
                temp = temp->parent;

            } else {
                if (!w->left->color) {
                    w->right->color = 0;
                    w->color = 1;
                    rbtree_left_rotate(root, sentinel, w);
                    w = temp->parent->left;
                }

                w->color = temp->parent->color;
                temp->parent = 0;
                w->left->color = 0;
                rbtree_right_rotate(root, sentinel, temp->parent);
                temp = *root;
            }
        }
    }

    temp->color = 0;
}

rbtree_node* rbtree_min(rbtree *tree) {
    if(!tree->root || tree->root == tree->sentinel) {
        return nullptr;
    }

    return rbtree_min(tree->root, tree->sentinel);
}

rbtree_node* rbtree_max(rbtree *tree) {
    if(!tree->root || tree->root == tree->sentinel) {
        return nullptr;
    }

    return rbtree_max(tree->root, tree->sentinel);
}

rbtree_node* ngx_rbtree_next(rbtree *tree, rbtree_node *node)
{
    rbtree_node* root = nullptr;
    rbtree_node* sentinel = nullptr;
    rbtree_node* parent = nullptr;

    sentinel = tree->sentinel;

    if (node->right != sentinel) {
        return rbtree_min(node->right, sentinel);
    }

    root = tree->root;

    for ( ;; ) {
        parent = node->parent;

        if (node == root) {
            return nullptr;
        }

        if (node == parent->left) {
            return parent;
        }

        node = parent;
    }
}

        再对之前的main.cpp进行一些更改:

//main.cpp

#include "minheap.h"
#include "rbtree.h"

#include <cstdint>
#include <iostream>
#include <functional>
#include <chrono>
#include <ctime>
#include <thread>

enum TimeType {
    MIN_HEAP,
    RBTREE,
};

extern "C"{
#define offsetofs(s,m) (size_t)(&reinterpret_cast<const volatile char&>((((s*)0)->m)))
#define container_of(ptr, type, member) ({                  \
    const typeof( ((type *)0)->member ) *__mptr = (ptr);    \
    (type *)( (char *)__mptr - offsetofs(type, member) );})
}

using CallBack = std::function<void(void)>;

struct TimeNode {
    timer_entry env;
    CallBack cb;
};

struct TimeNodeRb {
    rbtree_node env;
    CallBack cb;
};

class Timer {
public:
    Timer(uint32_t size);
    Timer(uint32_t size, TimeType Type);
    Timer() = delete;
    ~Timer();

    int addTimer(uint64_t time, CallBack cb);

    void run();

    void stop();

private:
    uint64_t GetNowTime();

    void AddMinHeapTimer(uint64_t time, CallBack cb);

    void AddRbtreeTimer(uint64_t time, CallBack cb);
private:
    min_heap* _heap;
    rbtree*   _rbtree;
    bool _close;
    TimeType _Type;
};

Timer::Timer(uint32_t size) {
    min_heap_init(&_heap, size);
    _close = false;
}

Timer::Timer(uint32_t size, TimeType Type) {
    switch (Type) {
    case  MIN_HEAP:
        min_heap_init(&_heap, size);
        break;
    case RBTREE:
        _rbtree = new rbtree();
        if(_rbtree) {
            _rbtree->sentinel = new rbtree_node();
            rbtree_init(_rbtree, _rbtree->sentinel);
        }
        break;
    }
    _close = false;
    _Type = Type;
}

Timer::~Timer() {
    switch (_Type) {
    case MIN_HEAP:
        min_heap_free(_heap);
        break;
    case RBTREE:
        delete _rbtree->sentinel;
        delete _rbtree;      
        break;
    }
}

int Timer::addTimer(uint64_t time, CallBack cb) {
    switch (_Type) {
    case MIN_HEAP:
        AddMinHeapTimer(time, cb);
        break;
    case RBTREE:
        AddRbtreeTimer(time, cb);
        break;
    }
    return 0;
}

uint64_t Timer::GetNowTime() {
    auto now = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
    uint64_t timestamp_ms = duration.count();
    return timestamp_ms;
}

void Timer::run() {
    while(!_close) {
        uint64_t sleep = 50;
        uint64_t now = GetNowTime();
        switch (_Type) {
            case MIN_HEAP: {
                timer_entry *entry = nullptr;
                if (!min_heap_top(_heap, &entry)) {
                    if (entry->time <= now) {
                        if (!min_heap_pop(_heap, &entry)) {
                            TimeNode *node = container_of(entry, TimeNode, env);
                            if (node) {
                                node->cb();
                            }

                            delete node;
                        }
                    } else {
                        sleep = entry->time - now;
                    }
                }
            }
            case RBTREE: {
                rbtree_node* node = rbtree_min(_rbtree);
                if(!node) {
                    break;
                }

                if(node->key <= now) {
                    rbtree_delete(_rbtree, node);
                    TimeNodeRb* n = container_of(node, TimeNodeRb, env);
                    n->cb();

                    delete n;
                } else {
                    sleep = node->key - now; 
                }
            }
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(sleep));
    }
}


void Timer::stop() {
    _close = true;
}

void Timer::AddMinHeapTimer(uint64_t time, CallBack cb) {
    TimeNode* node = new TimeNode();
    node->env.time = GetNowTime() + time;
    node->cb = cb;
    min_heap_push(_heap, &node->env);
}

void Timer::AddRbtreeTimer(uint64_t time, CallBack cb) {
    TimeNodeRb* node = new TimeNodeRb();
    node->env.key = GetNowTime() + time;
    node->cb = cb;
    rbtree_insert(_rbtree, &node->env);
}

int main(int, char**){

    Timer timer(0, RBTREE);

    auto now = std::chrono::high_resolution_clock::now();
    auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
    uint64_t timestamp_ms = duration.count();
    std::cout << "Start, now time :" << timestamp_ms << std::endl;
    timer.addTimer(1000, [&](void){
        auto now = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
        uint64_t timestamp_ms = duration.count();
        std::cout << "timer 1, now time :" << timestamp_ms << std::endl;
    });

    timer.addTimer(2000, [&](void){
        auto now = std::chrono::high_resolution_clock::now();
        auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
        uint64_t timestamp_ms = duration.count();
        std::cout << "timer 2, now time :" << timestamp_ms << std::endl;
    });

    std::thread t([&](){
        timer.run();
    });
    std::this_thread::sleep_for(std::chrono::milliseconds(3000));
    timer.stop();
    t.join();

    return 0;
}

 4.运行效果

         

        整个工程放在Github 上,感兴趣可以直接clone下来用构建运行。

学习参考:0voice · GitHub    

   

标签:黑树,之红,定时器,node,temp,parent,color,rbtree,left
From: https://blog.csdn.net/weixin_55951019/article/details/144324854

相关文章

  • 基于链表的定时器管理(三)
    5.启动定时器(timer_start)(工作中经常用到)timer_start函数接收定时器的过期时间和回调函数,并将定时器节点插入到定时器链表中。inttimer_start(timer_list_t*timer_list,timer_node_t*timer_node,UINT32expire_time,......
  • 面试考题:定时器底层逻辑
    前言让我们回想一下关于定时器的内容,我们只知道,他是在我们设置的时间后才异步执行的程序。可在面试时回答这个就够了吗?那当然是不够的。本文将带你深入了解定时器底层定义我们先了解什么是定时器。在JavaScript中,定时器是一种用于延迟执行代码或定期执行代码的机制。它......
  • 树--红黑树
    红黑树介绍红黑树(RedBlackTree)是一种自平衡二叉查找树。它是在1972年由RudolfBayer发明的,当时被称为平衡二叉B树(symmetricbinaryB-trees)。后来,在1978年被LeoJ.Guibas和RobertSedgewick修改为如今的“红黑树”。由于其自平衡的特性,保证了最坏情形下在O(l......
  • JavaScript定时器
    1.setInterval(functiontime)周期定时器vari=0setInterval(function(){console.log(i++)},3000)//3000指的是3000毫秒也就是3s//这个事件会每隔三秒显示一个i每次i++2.setTimeout延迟定时器setTimeout(function(){console.log(i++)},3000)//这个是打......
  • 【C++】7000字剖析红黑树的概念规则和底层代码实现
    目录一、红黑树的概念二、怎么做到最长路径与最短路径相差小于等于两倍?(性质)     三、极端场景分析最长路径和最短路径:四、AVL树和红黑树的效率对比:五、树的路径包括叶子结点的空结点六、红黑树的插入结点时的相关规则:(一)、插入结点的颜色必须为红色(二)、处理规......
  • 切换标签窗口后js定时器自动停止了,如何在激活标签后又继续呢?
    JavaScript定时器在标签页失去焦点(例如切换到其他标签页或最小化浏览器)时,会被浏览器降低优先级或暂停,以节省资源。这会导致定时器不准确,甚至看起来停止了。要解决这个问题,你需要使用requestAnimationFrame或手动调整时间差。1.使用requestAnimationFrame(推荐)requestAnim......
  • 定时器实现之最小堆(一)
    1.概述        定时器是一种用于在指定时间后执行特定任务或操作的机制。在计算机科学和编程中,定时器通常用于实现延时操作、周期性任务调度等功能。         对于定时器的实现,核心分为两大块,分别是容器和触发方式,容器就是组织定时器中定时任务的数据结构,触......
  • 【Go底层】time包Ticker定时器原理
    目录1、背景2、go版本3、源码解释【1】Ticker结构【2】NewTicker函数解释4、代码示例5、总结1、背景说到定时器我们一般想到的库是cron,但是对于一些简单的定时任务场景,标准库time包下提供的定时器就足够我们使用,本篇文章我们就来研究一下time包下的Ticker定时器。2......
  • Qt - QTimer(定时器)
    基本使用方式:多次定时器QTimer*timer=newQTimer(this);//timer->setInterval(1000);//设置间隔时间connect(timer,SIGNAL(timeout()),this,SLOT(update()));timer->start(1000);//start之后,设置间隔时间并启动定时器,每隔一秒触发一次槽函数 单次定时器注意:可......
  • 一文带你了解HVV实战攻防演练之红队攻击,零基础入门到精通,收藏这一篇就够了!
    0x00什么是红队红队,一般是指网络实战攻防演习中的攻击一方。红队一般会针对目标系统、人员、软件、硬件和设备同时执行的多角度、混合、对抗性的模拟攻击;通过实现系统提权、控制业务、获取数据等目标,来发现系统、技术、人员和基础架构中存在的网络安全隐患或薄弱环节。红......