数据结构(7)之红—黑树

概念
红黑树是一种自平衡二叉查找树,是在计算机科学中用到的一种数据结构,典型的用途是实现关联数组。它是在1972年由Rudolf Bayer发明的,他称之为"对称二叉B",它现代的名字是在Leo J. Guibas Robert Sedgewick 1978年写的一篇论文中获得的。它是复杂的,但它的操作有着良好的最坏情况运行时间,并且在实践中是高效的: 它可以在O(log n)时间内做查找,插入和删除,这里的n 是树中元素的数目。
  红黑树是一种很有意思的平衡检索树。它的统计性能要好于平衡二叉树(有些书籍根据作者姓名,Adelson-VelskiiLandis,将其称为AVL-),因此,红黑树在很多地方都有应用。在C++ STL中,很多部分(目前包括set,multiset, map, multimap)应用了红黑树的变体(SGI STL中的红黑树有一些变化,这些修改提供了更好的性能,以及对set操作的支持)

性质
  红黑树是每个节点都带有颜色属性的二叉查找树,颜色或红色或黑色。在二叉查找树强制一般要求以外,对于任何有效的红黑树我们增加了如下的额外要求:
  性质1. 节点是红色或黑色。
  性质2. 根是黑色。
  性质3. 所有叶子都是黑色(叶子是NIL节点)。
  性质4. 每个红色节点的两个子节点都是黑色。(从每个叶子到根的所有路径上不能有两个连续的红色节点)
  性质5. 从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
  
  这些约束强制了红黑树的关键性质: 从根到叶子的最长的可能路径不多于最短的可能路径的两倍长。结果是这个树大致上是平衡的。因为操作比如插入、删除和查找某个值的最坏情况时间都要求与树的高度成比例,这个在高度上的理论上限允许红黑树在最坏情况下都是高效的,而不同于普通的二叉查找树。
  要知道为什么这些特性确保了这个结果,注意到属性4导致了路径不能有两个毗连的红色节点就足够了。最短的可能路径都是黑色节点,最长的可能路径有交替的红色和黑色节点。因为根据属性5所有最长的路径都有相同数目的黑色节点,这就表明了没有路径能多于任何其他路径的两倍长。

一种红黑树的实现方法:

/**
*
红黑树的实现
**/

public class RBTreeTest<E extends Comparable<E>> {
    static enum Color {
        BLACK, RED
    }
   
    static class RBPrinter {
        public static void visitNode(RBNodenode) {
            RBNode n =node;
            if (n !=null)
               System.out.print(n.key + "("
                       + (n.color == Color.RED ? "RED" : "BLACK")
                       + "),");
        }
    }

    static class RBNode<E extendsComparable<E>> {
        E key;

        RBNode<E>left, right;

        RBNode<E>parent;

        Color color;

       RBNode(RBNode<E> p, E key, Color color) {
            this.key =key;
            this.color =color;
            this.parent= p;
            this.left =null;
            this.right =null;
        }
    }

    private RBNode<E> root;

    public RBTreeTest() {
        root = null;
    }

    public boolean isEmpty() {
        return root == null;
    }

    public E findMax() {
        if (isEmpty())
            return null;
        RBNode<E> node = root;
        while ((node.right) != null) {
            node =node.right;
        }
        return node.key;
    }

    public E findMin() {
        if (isEmpty())
            return null;
        RBNode<E> node = root;
        while ((node.left) != null) {
            node =node.left;
        }
        return node.key;
    }

    public final boolean contains(E ele) {
        RBNode<E> tmp = root;
        int cmp = -1;
        while (tmp != null) {
            cmp =ele.compareTo(tmp.key);
            if (cmp <0) {
               tmp = tmp.left;
            } else if(cmp > 0) {
               tmp = tmp.right;
            } else {
               return true;
            }
        }
        return false;
    }

    public final boolean delete(E ele) {
        RBNode<E> cur;
        int cmp;
        if (root == null)
            returnfalse;
        cur = root;
        while (cur != null && (cmp =ele.compareTo(cur.key)) != 0) {
            if (cmp <0)
               cur = cur.left;
            else
               cur = cur.right;
        }
        if (cur == null) {
            returnfalse;
        }
        if ((cur.left) != null &&(cur.right) != null) {
           RBNode<E> prev = cur.left;
            while((prev.right) != null) {
               prev = prev.right;
            }
            cur.key =prev.key;
            cur = prev;
        }
        if ((cur.left) != null) {
            if (cur ==root) {
               root = cur.left;
               root.color = Color.BLACK;
               return true;
            }
            if(cur.parent.left == cur) {
               cur.parent.left = cur.left;
               cur.left.parent = cur.parent;
            } else {
               cur.parent.right = cur.left;
               cur.left.parent = cur.parent;
            }
            if(cur.color == Color.BLACK) {
               cur.left.color = Color.BLACK;
            }
        } else if ((cur.right) != null) {
            if (cur ==root) {
               root = cur.right;
               root.color = Color.BLACK;
               return true;
            }
            if(cur.parent.left == cur) {
               cur.parent.left = cur.right;
               cur.right.parent = cur.parent;
            } else {
               cur.parent.right = cur.right;
               cur.right.parent = cur.parent;
            }
            if(cur.color == Color.BLACK) {
               cur.right.color = Color.BLACK;
            }
        } else {
            if (cur ==root) {
               root = null;
               return true;
            }
           RBNode<E> todo;
            if(cur.parent.left == cur) {
               todo = null;
               cur.parent.left = todo;
            } else {
               todo = null;
               cur.parent.right = todo;
            }
            if(cur.color == Color.BLACK) {
               fixupDoubleBlack(todo);
            }
        }
        return true;
    }

    private final voidfixupDoubleBlack(RBNode<E> cur) {
        RBNode<E> sibling;
        RBNode<E> p;

        while (cur !=root) {
            p =cur.parent;
            if (p.left== cur) {
               sibling = p.right;
               if (sibling.color == Color.RED) {
                   rotateLeft(p);
                   p.color = Color.RED;
                   sibling.color = Color.BLACK;
               } else {
                   if (sibling.right.color == Color.RED) {
                       rotateLeft(p);
                       p.color = Color.BLACK;
                       sibling.right.color = Color.BLACK;
                       return;
                   } else if (sibling.left.color == Color.RED) {
                       rotateRight(sibling);
                       sibling.color = Color.RED;
                       sibling.parent.color = Color.BLACK;
                   } else {
                       sibling.color = Color.RED;
                       if (p.color == Color.BLACK) {
                           cur = p;
                       } else {
                           p.color = Color.BLACK;
                           return;
                       }
                   }
               }
            } else {
               sibling = p.left;
               if (sibling.color == Color.RED) {
                   rotateRight(p);
                   p.color = Color.RED;
                   sibling.color = Color.BLACK;
               } else {
                   if (sibling.left.color == Color.RED) {
                       rotateRight(p);
                       sibling.color = p.color;
                       p.color = Color.BLACK;
                       sibling.left.color = Color.BLACK;
                       return;
                   } else if (sibling.right.color == Color.RED) {
                       rotateLeft(sibling);
                       sibling.color = Color.RED;
                       sibling.parent.color = Color.BLACK;
                   } else {
                       sibling.color = Color.RED;
                       if (p.color == Color.BLACK) {
                           cur = p;
                       } else {
                           p.color = Color.BLACK;
                           return;
                       }
                   }
               }
            }
        }
    }

    public final void insert(E ele) {
        if (root == null) { //
添加根节点
            root = newRBNode<E>(null, ele, Color.BLACK);
            return;
        } else { //
将该节点添加到合适的叶子节点的位置
           RBNode<E> parent = null;
           RBNode<E> cur = root;
            int cmp =-1;
            while (cur!= null && (cmp = ele.compareTo(cur.key)) != 0) {
               parent = cur;
               if (cmp < 0)
                   cur = cur.left;
               else
                   cur = cur.right;
            }
            if (cmp ==0) { //
不能添加相同的元素
               throw new IllegalArgumentException(
                       "can't insert duplicate key!");
            }
            cur = newRBNode<E>(parent, ele, Color.RED);
            if (cmp <0) { //
添加为左孩子
               parent.left = cur;
            } else { //
添加为右孩子
               parent.right = cur;
            }

           insertFixup(cur); // 调整各个节点
        }
    }

    private final voidinsertFixup(RBNode<E> cur) {
        RBNode<E> p, g;
        while (cur != root &&cur.color == Color.RED) {
            p =cur.parent;
            if (p.color== Color.BLACK) {
               return;
            }
            g =p.parent;
            if (p ==g.left) { // p
g的左子树
               RBNode<E> uncle = g.right;
               if (uncle != null && uncle.color == Color.RED) {
                   g.color = Color.RED;
                   uncle.color = p.color = Color.BLACK;
                   cur = g;
               } else {
                   if (cur == p.right) {
                       cur = rotateLeft(p);
                       cur = cur.left;
                   }
                   cur = rotateRight(g);
                   cur.color = Color.BLACK;
                   cur.left.color = cur.right.color = Color.RED;
               }
            } else { // p
g的右子树
               RBNode<E> uncle = g.left;
               if (uncle != null && uncle.color == Color.RED) {
                   g.color = Color.RED;
                   uncle.color = p.color = Color.BLACK;
                   cur = g;
               } else {
                   if (cur == p.left) {
                       cur = rotateRight(p);
                       cur = cur.right;
                   }
                   cur = rotateLeft(g);
                   cur.color = Color.BLACK;
                   cur.left.color = cur.right.color = Color.RED;
               }
            }
        }
        root.color = Color.BLACK;
    }

    /*
     *     gr          gr           gr  
     *    /           /             /  
     *   p                           ch
     *   / \   =>   p ch   =>   /\         ch
绕着父节点p左旋(即将父节点p和它的右孩子转换角色)
     * 1 ch      /      \         p    3
     *     / \    1   2    3      / \
     *   2   3                  1    2
     */

    private final RBNode<E> rotateLeft(RBNode<E> p){
        RBNode<E> gr =p.parent;//grandfather
        RBNode<E> ch =p.right;    //children
        p.right = ch.left;
        if (ch.left != null) {
           ch.left.parent = p;
        }
        ch.left = p;
        p.parent = ch;
   
        if (gr != null) {    //p
不是root节点
            if (gr.left== p)    //
如果pgr的左孩子
               gr.left = ch;
           else                //p
gr的右孩子
               gr.right = ch;
        } else{            //p
root节点
           root = ch;
        }
        ch.parent = gr;
        return ch;
    }
   
   /*
     *      gr          gr           gr  
     *     /            /              /  
     *    p                          ch
     *    / \   =>  ch p   =>   /\         ch
绕着父节点p右旋(即将父节点p和它的左孩子转换角色)
     *   ch 3     /      \        1   p
     *   /\         1  2   3           / \
     * 1   2                        2   3
     */
    private final RBNode<E>rotateRight(RBNode<E> p) {
        RBNode<E> gr = p.parent;
        RBNode<E> ch = p.left;
        p.left = ch.right;
        if (ch.right != null) {
           ch.right.parent = p;
        }
        ch.right = p;
        p.parent = ch;
        if (gr != null) {
            if (gr.left== p)
               gr.left = ch;
            else
               gr.right = ch;
        } else {
            root = ch;
        }
        ch.parent = gr;
        return ch;
    }
   
    public void inOrder(){
        inOrder(root);
    }
   
    private void inOrder(RBNode<E> cur) {
        if(cur != null){
           inOrder(cur.left);
           RBPrinter.visitNode(cur);
           inOrder(cur.right);
        }
    }

    public static void main(String[] args) {
        java.util.Random ran = newjava.util.Random();
        RBTreeTest<Integer> rbt = newRBTreeTest<Integer>();
        int tmp = 0;
        for(int i=0;i<15;i++){
            tmp =ran.nextInt(1000);
            try{
               rbt.insert(tmp);
            } catch(IllegalArgumentException e){
               do{
                   tmp = ran.nextInt(1000);
               }while(rbt.contains(tmp));
               rbt.insert(tmp);
            }
           System.out.println(tmp);
        }
       
        System.out.print("\nInorderbegin:\n");
        rbt.inOrder();
        System.out.print("\nInorderend\n");
       
        rbt.delete(tmp);
       
        System.out.print("\nInorderbegin:\n");
        rbt.inOrder();
        System.out.print("\nInorderend\n");
    }
}

源码来自:https://pan.quark.cn/s/a4b39357ea24 《C++ Primer》作为C++编程领域中的一部权威著作,主要服务于初学者和经验丰富的开发者,致力于帮助他们深入掌握C++的核心知识。 第一章通常会详细讲解C++语言的基础概念和语法结构,包括变量的使用、数据类型的分类、常量的定义、运算符的应用以及基础的输入输出操作。 接下来,我们将对这一章中的核心知识点和可能的习题解答进行深入分析。 ### 1. 变量与数据类型在C++编程中,变量被视为存储数据的媒介。 每一个变量都必须预先声明其数据类型,常见的数据类型有整型(int)、浮点型(float)、双精度浮点型(double)以及字符型(char)。 例如:```cppint age = 25; // 声明一个整型变量age并赋予其初始值25float weight = 70.5f; // 声明一个浮点型变量weight并赋予其初始值70.5char grade = A; // 声明一个字符型变量grade并赋予其初始值A```### 2. 常量与字面量常量指的是不可更改的值,可以通过`const`关键字进行声明。 例如:```cppconst int MAX_SIZE = 100; // 声明一个整型常量MAX_SIZE,其值为100```字面量是指程序中直接书写的值,如`42`、`3.14`或`"Hello"`。 ### 3. 运算符C++提供了多种运算符,涵盖了算术运算符(+,-,*,/,%)、比较运算符(==,!=,<,>,<=,>=)、逻辑运算符(&&,||,!)以及赋值运算符(=,+=,-=,*=,/=,%=)等。 ### 4. 输入与输出在C++中,使用`std::cin`来实现输...
内容概要:本文详细介绍了一个基于C++的仓库存储管理系统的设计与实现,涵盖了项目背景、目标、挑战及解决方案,并系统阐述了整体架构设计、数据库建模、功能模块划分、权限安全、并发控制、数据一致性保障、异常处理与可扩展性等关键内容。通过面向对象编程思想,采用分层架构与模块化解耦设计,结合STL容器、多线程、锁机制等C++核心技术,实现了高效的库存管理功能,包括入库、出库、盘点、调拨、权限控制、日志追踪与智能报表分析。文中还提供了核心类如Inventory(库存)、User(用户权限)、LogEntry(操作日志)及WarehouseManager(主控制器)的代码示例,展示了数据结构设计与关键算法逻辑。; 适合人群:具备C++编程基础,熟悉面向对象设计与基本数据结构的软件开发人员,尤其适合从事企业级管理系统开发或希望深入理解系统架构设计的中级开发者(工作1-3年);也适用于计算机相关专业学生进行课程设计或毕业项目参考; 使用场景及目标:①学习如何使用C++构建复杂业务系统的整体架构与模块划分方法;②掌握高并发、数据一致性、权限控制、异常处理等企业级系统关键技术的实现思路;③理解仓储管理业务流程及其在软件系统中的建模与落地方式;④为开发类似ERP、MES等后台管理系统提供技术原型与设计参考; 阅读建议:此资源不仅提供理论架构与代码片段,更强调系统设计的完整性与工程实践性。建议读者结合代码示例动手实现核心模块,深入理解类之间的关系与交互逻辑,重点关注多线程安全、事务管理与权限校验等难点环节,并尝试扩展功能如对接GUI界面或数据库持久化模块,以全面提升系统开发能力。
农作物叶子健康与疾病实例分割数据集 一、基础信息 数据集名称:农作物叶子健康与疾病实例分割数据集 图片数量: - 训练集:7,446张图片 - 验证集:970张图片 - 测试集:182张图片 - 总计:8,598张图片 分类类别: - Apple Healthy(健康苹果叶) - Apple Rust Leaf(苹果锈病叶) - Apple Scab Leaf(苹果星病叶) - BellPepper Healthy(健康甜椒叶) - BellPepper Leaf Spot(甜椒叶斑病) - Corn Gray Leaf Spot(玉米灰斑病) - Corn Leaf Blight(玉米叶枯病) - Corn Rust Leaf(玉米锈病叶) - Grape Black Rot(葡萄腐病) - Grape Healthy(健康葡萄叶) - Squash Powdery Leaf(南瓜白粉病叶) - Tomato Bacterial Spot(番茄细菌性斑点病) - Tomato Healthy(健康番茄叶) - Tomato Septoria(番茄斑枯病) 标注格式:YOLO格式,包含实例分割的多边形标注,适用于实例分割任务。 数据格式:图片来源于农业图像数据库,细节清晰。 二、适用场景 农业植物疾病AI检测系统开发:数据集支持实例分割任务,帮助构建能够自动识别植物叶子疾病区域并分类的AI模型,辅助农民快速诊断和治理。 精准农业应用研发:集成至农业智能管理系统中,提供实时疾病识别功能,为农作物健康管理提供决策支持。 学术研究与创新:支持农业科学与人工智能交叉领域的研究,助力发表高水平农业AI论文。 农业教育与培训:数据集可用于农业院校或培训机构,作为学生学习植物疾病分类和诊断的重要资源。 三、数据集优势 精准标注与多样性:每张图片均经过准确标注,确保疾病区域分割精确。包
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值