IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> PHP知识库 -> 你了解红黑树么?告诉你一个不一样的红黑树,说点有意思的吧! -> 正文阅读

[PHP知识库]你了解红黑树么?告诉你一个不一样的红黑树,说点有意思的吧!

先看如下两个问题:

问题1、红黑树的键值可以重复么?
问题2、红黑树必须有键值么?

关于红黑树的介绍网上非常多,红黑树的应用也非常广泛。问一下度娘,她会告诉你各种各样的实现方法,C和C++版本都有,linux内核使用的版本也有。代码都大同小异,就是插入或删除时如何修正,如何搞平衡。很多文章图文并茂、写实而生动,当你在脑海里试图左旋一把,右旋一把搞平衡时,基本也到了精神崩溃的边缘。

如何维护祖孙三代父、祖父、叔叔以及兄弟间的平衡,如何搞好家庭关系,是个头疼的问题。如果把红黑树比作一个族谱的话,可能开始你是高祖,下个节点插进去后就变成了太宗,随着族系的繁衍最后你可能变成个哀帝。开始A是B爸爸,过会B又变成A爸爸,甚至是爷爷,叔叔、兄弟,你说乱不乱,烧脑烧脑,气人不气人。
套用郭德纲在相声中对于谦说的话:到了咱们这个年纪,谁是谁爸爸都无所谓了。台上无大小,台下立规矩,送给台上的各种二叉树。

这里先介绍一个朴实无华的网站:可视化的数据结构和算法教学,非常不错,里面有经典数据结构的动态展现,可以将你从各种旋转中解救出来。如下图:

在这里插入图片描述

说了这么多回到本文开头的两个问题:

问题1:红黑树的键值可以重复么?

大部分人可能认为不可以重复,因为重复的键值会冲突或没有现实意义。其实是可以重复的。为了表达对二叉树的敬意,这里连续插入多个2。使用上面安利的网站,建立了一个很2的红黑树。如下图:

在这里插入图片描述
上面的红黑树键值都相等,非常不可思议,但它确实是棵红黑树。
那么这颗很2的红黑树的现实意义是什么,能应用到什么地方?当然有,而且很广泛,这个地方就是定时器,对于大部分服务器程序,基本都要实现自己的定时器,从而完成一些特殊的重复性工作,比如nodejs的引擎libuv库中的定时器,nginx中的定时器、以及redis的键值有效期判断等。。。。

当管理多个定时器时就会存在键值相等的节点,也就是到期时间相等的节点。这时候如何判断谁先执行呢?
下面是libuv定时器实现的部分关键代码:

// libuv定时器使用回调函数来比较key的大小,这里的key就是到期时间timeout
static int timer_less_than(const struct heap_node* ha,
                           const struct heap_node* hb) {
  const uv_timer_t* a;
  const uv_timer_t* b;

  a = container_of(ha, uv_timer_t, heap_node);
  b = container_of(hb, uv_timer_t, heap_node);

  if (a->timeout < b->timeout)
    return 1;
  if (b->timeout < a->timeout)
    return 0;

  /* Compare start_id when both have the same timeout. start_id is
   * allocated with loop->timer_counter in uv_timer_start().
   */
   // 如果两者过期时间相同,则采用start_id来判断谁先执行
   // 这个start_id是个自增变量,后加入堆中的定时器的start_id要大于早加入堆中的定时器
  return a->start_id < b->start_id;
}

// 定时器启动并加入到堆中的函数
int uv_timer_start(uv_timer_t* handle,
                   uv_timer_cb cb,
                   uint64_t timeout,
                   uint64_t repeat) {
  uint64_t clamped_timeout;

  if (uv__is_closing(handle) || cb == NULL)
    return UV_EINVAL;

  if (uv__is_active(handle))
    uv_timer_stop(handle);

  clamped_timeout = handle->loop->time + timeout;
  if (clamped_timeout < timeout)
    clamped_timeout = (uint64_t) -1;

  handle->timer_cb = cb;
  handle->timeout = clamped_timeout;
  handle->repeat = repeat;
  /* start_id is the second index to be compared in timer_less_than() */
  handle->start_id = handle->loop->timer_counter++;

  // 将定时器插入堆中,并使用timer_less_than函数进行堆排序
  heap_insert(timer_heap(handle->loop),
              (struct heap_node*) &handle->heap_node,
              timer_less_than);
  uv__handle_start(handle);

  return 0;
}

libuv使用的是最小堆来保存和管理多个定时器,在排序的过程中如果发现时间相等的节点(见上面函数 timer_less_than),则采用start_id来比较大小,这个start_id是个自增变量,后加入堆中的定时器的start_id要大于早加入堆中的定时器 。从而来判断键值相等的到期事件谁先执行。

回到上面的红黑树,如果你仔细观察这颗树的创建过程就会发现,对于键值相同的节点是有时间顺序的,插入晚的默认为大值,放在后面,也就是说红黑树自动实现了按时间轴存储键值的功能。即使到期事件相等(键值Key相等),我们也可以根据其插入红黑树的时间顺序来取出最小到期事件去执行。

nginx使用的就是红黑树的方式来存储和管理多个定时器。这里就不再介绍了。

问题2、红黑树必须有键值么?

这棵树也是可以创建的,只不过看上去比上面很2的树还难理解。
上面libuv的定时器节点大小比较函数 timer_less_than已经告诉我们了,你是可以在比较节点的时候不依赖于key值,在你的插入节点时,通过回调函数来告诉节点谁是“大”的谁是“小”的,这个大小不是数学意义上的大小,可能是业务上一个逻辑业务的大小。通过一系列多个指标而非单一key,来评估一个节点的在业务上而非数学上的前后顺序。比如个人信用的评估,可能要根据多项指标(年龄、工龄、消费记录等)来计算出一个所谓的“大小”值。

写的太多了,需要上班就此打住,权当抛砖引玉吧。

感谢您的阅读!

  PHP知识库 最新文章
Laravel 下实现 Google 2fa 验证
UUCTF WP
DASCTF10月 web
XAMPP任意命令执行提升权限漏洞(CVE-2020-
[GYCTF2020]Easyphp
iwebsec靶场 代码执行关卡通关笔记
多个线程同步执行,多个线程依次执行,多个
php 没事记录下常用方法 (TP5.1)
php之jwt
2021-09-18
上一篇文章      下一篇文章      查看所有文章
加:2021-09-03 11:40:27  更:2021-09-03 11:41:48 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 21:30:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计