数据结构——红黑树

2023-09-18 17:40:21

红黑树(Red-Black Tree)是一种自平衡的二叉查找树,它确保在插入和删除等基本操作后,树保持平衡,从而提供了快速的查找、插入和删除操作。红黑树之所以称为"红黑树",是因为每个节点都具有一个颜色属性,可以是红色或黑色,它们必须满足一些规则以保持树的平衡性。
性质:
1.树中的任何一个结点都带有颜色, 每个结点的颜色要么是红色, 要么是黑色
2.根结点是黑色
3.所有叶子结点是黑色(在红黑树中, 我们将底层叶结点看做有两个值为 NULL 的孩子结点, 以 NULL 结点作为红黑树的叶结点)
4.每个红色结点的孩子结点一定是黑色
5.对于树中的任意一个结点, 从该结点到所有叶结点的路径上一定包含相同数量的黑结点(我们将红黑树任意结点到叶子结点的路径上的黑色结点的个数称为该结点的 「黑高」)

根据性质得出:
1.没有一条路径比其他路径长出2倍
2.树的高度稳定趋近于log-n
3.一棵有n个节点的红黑树的高度,最多是两倍的2(log(n+1))

在这里插入图片描述
请添加图片描述

左旋操作(Left Rotation)
左旋是一种将节点向左移动的操作,通常用于修复红黑树的性质。左旋的基本思想是将一个节点的右子节点提升为新的父节点,同时原来的父节点成为新的左子节点。这可以保持二叉搜索树的性质,并且确保红黑树的平衡。

右旋操作(Right Rotation)
右旋是一种将节点向右移动的操作,也用于修复红黑树的性质。右旋的基本思想是将一个节点的左子节点提升为新的父节点,同时原来的父节点成为新的右子节点。这同样可以保持二叉搜索树的性质,并确保红黑树的平衡。

#include <iostream>

enum class Color { RED, BLACK };

template <typename T>
struct Node {
    T data;
    Node* parent;
    Node* left;
    Node* right;
    Color color;
};

template <typename T>
class RedBlackTree {
private:
    Node<T>* root;

    // 左旋转
    void leftRotate(Node<T>* x) {
        Node<T>* y = x->right;
        x->right = y->left;
        if (y->left != nullptr) {
            y->left->parent = x;
        }
        y->parent = x->parent;
        if (x->parent == nullptr) {
            root = y;
        } else if (x == x->parent->left) {
            x->parent->left = y;
        } else {
            x->parent->right = y;
        }
        y->left = x;
        x->parent = y;
    }

    // 右旋转
    void rightRotate(Node<T>* y) {
        Node<T>* x = y->left;
        y->left = x->right;
        if (x->right != nullptr) {
            x->right->parent = y;
        }
        x->parent = y->parent;
        if (y->parent == nullptr) {
            root = x;
        } else if (y == y->parent->left) {
            y->parent->left = x;
        } else {
            y->parent->right = x;
        }
        x->right = y;
        y->parent = x;
    }

    // 插入节点修正
    void insertFixup(Node<T>* z) {
        while (z->parent != nullptr && z->parent->color == Color::RED) {
            if (z->parent == z->parent->parent->left) {
                Node<T>* y = z->parent->parent->right;
                if (y != nullptr && y->color == Color::RED) {
                    z->parent->color = Color::BLACK;
                    y->color = Color::BLACK;
                    z->parent->parent->color = Color::RED;
                    z = z->parent->parent;
                } else {
                    if (z == z->parent->right) {
                        z = z->parent;
                        leftRotate(z);
                    }
                    z->parent->color = Color::BLACK;
                    z->parent->parent->color = Color::RED;
                    rightRotate(z->parent->parent);
                }
            } else {
                Node<T>* y = z->parent->parent->left;
                if (y != nullptr && y->color == Color::RED) {
                    z->parent->color = Color::BLACK;
                    y->color = Color::BLACK;
                    z->parent->parent->color = Color::RED;
                    z = z->parent->parent;
                } else {
                    if (z == z->parent->left) {
                        z = z->parent;
                        rightRotate(z);
                    }
                    z->parent->color = Color::BLACK;
                    z->parent->parent->color = Color::RED;
                    leftRotate(z->parent->parent);
                }
            }
        }
        root->color = Color::BLACK;
    }

    // 插入节点
    void insert(Node<T>* z) {
        Node<T>* y = nullptr;
        Node<T>* x = root;
        while (x != nullptr) {
            y = x;
            if (z->data < x->data) {
                x = x->left;
            } else {
                x = x->right;
            }
        }
        z->parent = y;
        if (y == nullptr) {
            root = z;
        } else if (z->data < y->data) {
            y->left = z;
        } else {
            y->right = z;
        }
        z->left = nullptr;
        z->right = nullptr;
        z->color = Color::RED;
        insertFixup(z);
    }

    // 中序遍历
    void inorder(Node<T>* x) {
        if (x != nullptr) {
            inorder(x->left);
            std::cout << x->data << " ";
            inorder(x->right);
        }
    }

public:
    RedBlackTree() : root(nullptr) {}

    // 插入
    void insert(T data) {
        Node<T>* z = new Node<T>;
        z->data = data;
        z->left = nullptr;
        z->right = nullptr;
        z->color = Color::RED;
        insert(z);
    }

    // 中序遍历
    void inorder() {
        inorder(root);
    }
};

int main() {
    RedBlackTree<int> rbTree;
    rbTree.insert(10);
    rbTree.insert(20);
    rbTree.insert(30);
    rbTree.insert(40);
    rbTree.insert(50);
    rbTree.insert(60);
    rbTree.insert(70);

    std::cout << "Inorder Traversal of Red-Black Tree: ";
    rbTree.inorder();
    std::cout << std::endl;

    return 0;
}

更多推荐

influxdb2.7基本介绍安装与启动

概念timestamp:influxdb所有的数据都会有一个列_time来存timestamp。默认是以nanosecond格式存储的。field:field就是mysql中的字段,fieldkey存储在_field字段中,fieldvalue就是字段值,存储在_value字段中。fieldkey和fieldvalue

如何在微软Edge浏览器上一键观看高清视频?

编者按:视频是当下最流行的媒体形式之一。但由于视频压缩、网络不稳定等原因,我们常常可以看到互联网上的很多视频其画面质量并不理想,尤其是在浏览器端,这极大地影响了观看体验。不过,近期微软Edge浏览器推出了一项新功能,一键就可以让浏览器中的视频变为高清版。这项神奇功能背后的技术秘诀是什么?今天,让我们一起来了解一下微软E

selenium学习

selenium模块和爬虫之间的关联便捷的获取网站中动态加载的数据便捷实现模拟登录什么是selenium模块基于浏览器自动化的一个模块selenium使用流程:-环境安装:pipinstallselenium-下载一个浏览器的驱动程序(谷歌浏览器)-下载路径:http://chromedriver.storage.go

C++版本的OpenCV实现二维图像的卷积定理(通过傅里叶变换实现二维图像的卷积过程,附代码!!)

C++版本的OpenCV库实现二维图像的卷积定理过程详解前言一、卷积定理简单介绍二、不同卷积过程对应的傅里叶变换过程1、“Same”卷积2、“Full”卷积3、“Valid”卷积三、基于OpenCV库实现的二维图像卷积定理四、基于FFTW库实现的二维图像卷积定理五、总结与讨论前言工作中用到许多卷积过程,需要转成C++代

SpringBoot的配置环境属性

SpringBoot的配置环境属性在本文中,我们将讨论SpringBoot的配置环境属性。我们将了解如何使用这些属性来配置我们的应用程序,以便在不同的环境中运行。我们还将了解如何使用SpringBoot的配置文件来管理这些属性。最后,我们将介绍一些最佳实践,以帮助您更有效地使用这些属性。理解SpringBoot的配置环

《C和指针》笔记28:可变参数和stdarg宏

可变参数列表可以通过宏来实现,这些宏定义于stdarg.h头文件,它是标准库的一部分。这个头文件声明了一个类型va_list和三个宏——va_start、va_arg和va_end。我们可以声明一个类型为va_list的变量,与这几个宏配合使用,访问参数的值。下面的程序使用这三个宏计算指定数量的值的平均值。注意参数列表

linux和windows选哪个?

linux和windows选哪个?每年在大学中都会有这么一批学生:沉浸在安装Linux系统,安装双系统,使用Linux系统看看电影,搞一搞炫酷的桌面效果。最后收获了啥?怕是啥也没有,命令学会了几个?能不能写shell?这些才有点价值。最近很多小伙伴找我,说想要一些linux学习资料,然后我根据自己从业十年经验,熬夜搞了

【第四阶段】kotlin语言的Map集合学习

1.Map集合的创建packageKotlin.Stage4funmain(){valmap=mapOf("java"to1,"kotlin"to2)//java代表键1代表值valmap2=mapOf(Pair("java",1),Pair("kotlin",2))//和上面写法等价}2.读取map的值方式1:使用[

多输入多输出 | MATLAB实现LSSVM最小二乘支持向量机多输入多输出

多输入多输出|MATLAB实现LSSVM最小二乘支持向量机多输入多输出目录多输入多输出|MATLAB实现LSSVM最小二乘支持向量机多输入多输出预测效果基本介绍程序设计往期精彩参考资料预测效果基本介绍MATLAB实现LSSVM最小二乘支持向量机多输入多输出1.data为数据集,10个输入特征,3个输出变量。2.main

安防监控视频系统EasyCVR+AI算法智能分析网关助力智慧校园建设

学生是祖国的未来,学校就是培育学生的地方。随着校园信息化建设的不断发展,信息服务在校园管理中的作用也越来越强。在保障学生安全与校园高效管理上,人工智能做出了极大贡献,旭帆科技安防监控系统/视频汇聚/云存储/AI智能视频分析平台EasyCVR基于互联网、大数据、云计算的智慧管理,为提高校园监管标准,推进学校信息化建设,打

redis桌面连接工具Another Redis Desktop Manager使用介绍

AnotherRedisDesktopManager是一种类似于navicat的数据库连接工具,专门用来连接redis,使用起来非常简单方便,在这里推荐给大家。没有用过这个软件的,首先通过下面的网盘链接下载AnotherRedisDesktopManager百度网盘redis下载地址https://pan.baidu.

热文推荐