红黑树 java代码实现

文章目录

  • 代码实现
    • 节点实现类
    • 红黑树实现
  • 单元测试

代码实现

节点实现类

package csdn.dreamzuora.tree;/*** Title:* Description:** @version 1.0* @author: weijie* @date: 2020/10/19 13:30*/
public interface Node {
}
package csdn.dreamzuora.tree;import java.io.Serializable;/*** Title:* Description:** @version 1.0* @author: weijie* @date: 2020/10/19 13:27*/
public abstract class AbstractNode<T, E> implements Node, Serializable {private static final long serialVersionUID = -2321782309212147194L;/*** 数据域*/T data;/*** 左孩子*/E left;/*** 右孩子*/E right;public AbstractNode() {}public AbstractNode(T data) {this.data = data;}public T getData() {return data;}public void setData(T data) {this.data = data;}public E getLeft() {return left;}public void setLeft(E left) {this.left = left;}public E getRight() {return right;}public void setRight(E right) {this.right = right;}
}
package csdn.dreamzuora.tree;/*** Title: 红黑树节点* Description:** @version 1.0* @author: weijie* @date: 2020/10/21 14:36*/
public class RedBlackNode extends AbstractNode<Integer, RedBlackNode>  {/*** 红黑树节点颜色标记*/boolean isBlack;/*** 红黑树父亲节点*/RedBlackNode parent;public RedBlackNode(Integer data) {super(data);//默认为红色this.isBlack = false;}public boolean isBlack() {return isBlack;}public void setBlack(boolean black) {isBlack = black;}public RedBlackNode getParent() {return parent;}public void setParent(RedBlackNode parent) {this.parent = parent;}@Overridepublic String toString() {return "RedBlackNode{" +"isBlack=" + isBlack +", data=" + data +'}';}
}

红黑树实现

package csdn.dreamzuora.tree;import java.util.List;/*** Title: 树接口* Description:** @version 1.0* @author: weijie* @date: 2020/10/16 14:56*/
public interface Tree<T,E> {/*** 构建树* @param dataList*/void createTree(List<T> dataList);/*** 添加节点* @param data*/E addNode(E tree, T data);/*** 删除节点* @param tree* @param node*/void deleteNode(E tree, E node);/*** 前序遍历:根节点->左节点->右节点*/void preOrder(List<T> list, E node);/*** 中序遍历:左节点->根节点->右节点* @return*/void inOrder(List<T> list, E node);/*** 后序遍历:左节点->右节点->根节点*/void laOrder(List<T> list, E node);/*** 广度优先遍历:层序遍历* @param list* @param node*/void bfs(List<T> list, E node);}
package csdn.dreamzuora.tree;import java.io.Serializable;
import java.util.List;/*** Title: 二叉树抽象类* Description:** @version 1.0* @author: weijie* @date: 2020/10/16 14:57*/
public abstract class AbstractTree<T, E> implements Tree<T, E>, Serializable {private static final long serialVersionUID = -8046156919125106629L;/*** 根节点*/E root;@Overridepublic void createTree(List<T> dataList) {for (T data : dataList){addNode(root, data);}}void addNode(T data){};}
package csdn.dreamzuora.tree;import java.util.LinkedList;
import java.util.List;/*** Title: 红黑树* Description:* 规则:* 1.每个节点不是红色就是黑色* 2.每个根节点是黑色* 3.每个叶子节点就是黑色的空节点* 4.如果一个节点是红色的,则它的子节点必须是黑色的(父子不能同为红)* 5.平衡的关键字:从任一节点到其每个叶子的所有路径都包含相同的黑色的节点* 6.新插入节点默认为红色,插入后需要校验红黑树是否符合规则,不符合则需要进行平衡** 再平衡涉及到:左旋、右旋、颜色反转** 红黑树插入分为五种情况:** 1.新节点(A)位于树根,没有父节点*  直接让新节点变成黑色,规则二得到满足,同时,黑色的根节点使得每条路径上的黑色节点数目都增加1,所以*  并没有打破规则5*     A(红)  ->   A(黑)*   1  2        1  2*** 2.新节点(B)的父节点是黑色*   新插入的红色结点B并没有打破红黑树的规则,所以不需要做任何调整*          A(黑)*       B(红)  3*      1  2*** 3.新节点(D)的父节点和叔叔节点都是红色*            A(黑)               A(黑)                   A(红)*       B(红)    C(红)  ->   B(黑)    C(红)  -> ... ->B(黑)   c(黑)*      D(红) 3  4  5        D(红)                   D(红)*     1  2*经过上面的调整,这一局部重新符合了红黑树的规则* 4.新节点(D)的父节点是红色,叔叔节点是黑色或者没有叔叔,且新节点是父节点的右孩子,父节点(B)是祖父节点的左孩子* 我们以节点B为轴,做一次左旋,使得节点D成为父节点,原来的父节点B成为D的左孩子*       A(黑)                 A(黑)*    B(红)   C(黑)  ->   D(红)   C(黑)*   1  D(红) 4  5      B(红) 3  4  5*     2  3           1  2** 5.新节点(D)的父节点是红色,叔叔节点是黑色或者没有叔叔,且新节点是父节点的左孩子,父节点(B)*  是祖父节点的左孩子*  我们以节点A为抽,做一次右旋转,使得节点B成为祖父节点,节点A成为节点B的右孩子*         A(黑)                 B(红)                   B(黑)*      B(红)  C(黑)  ->      D(红)  A(黑)     ->    D(红)   A(红)*    D  3   4   5         1    2  3  C(黑)        1   2  3   C(黑)*  1  2                             4  5                    4  5** 颜色反转:* 如果当前节点、父节点、叔叔节点同为红色,这种情况违反了红黑树的规则,需求将红色向祖辈上传,* 父节点和叔叔节点变为黑色,爷爷节点变为黑->红色** 左旋:逆时针旋转红黑树的两个节点,使得父节点被自己的右孩子取代,而自己成为自己的左孩子*** 右旋:顺时针旋转红黑树的两个节点,使得父节点被自己的左孩子取代,而自己成为自己的右孩子** 时间负责度:logn* @version 1.0* @author: weijie* @date: 2020/10/19 17:39*/
public class RedBlackTree extends AbstractTree<Integer, RedBlackNode> {@Overridepublic void createTree(List<Integer> dataList) {for (Integer data : dataList){addNode(data);}}@Overridepublic void addNode(Integer data) {RedBlackNode node = new RedBlackNode(data);if (root == null){//根为黑色node.setBlack(true);root = node;return ;}RedBlackNode parent = root;RedBlackNode son = null;/*** 判断新节点是放在左子树还是右子树*/if (data <= parent.getData()){son = parent.getLeft();}else {son = parent.getRight();}/*** 对树深度遍历,寻找新节点存放的位置*/while (son != null){parent = son;if (data <= parent.getData()){son = parent.getLeft();}else {son = parent.getRight();}}/*** 节点插入*/if (data <= parent.getData()){parent.setLeft(node);}else {parent.setRight(node);}node.setParent(parent);/*** 自平衡*/balance(node);}@Overridepublic RedBlackNode addNode(RedBlackNode tree, Integer data) {return null;}/*** 自平衡* @param node*/private void balance(RedBlackNode node){RedBlackNode father;RedBlackNode grandFather;/*** 获取父节点并判断父节点是否为红色节点,规则:父子不同为红*/while ((father = node.getParent()) != null && father.isBlack() == false){//获取祖父节点grandFather = father.getParent();//判断父节点在祖先节点存在的位置if (grandFather.getLeft() == father){//叔叔节点RedBlackNode uncle = grandFather.getRight();//如果父亲、叔叔节点存在且都为红,则父亲、叔叔节点变为黑色if (uncle != null && uncle.isBlack() == false){father.setBlack(true);uncle.setBlack(true);grandFather.setBlack(false);//接着对祖先节点进行颜色反转node = grandFather;continue;}/*** 如果没有触发颜色反转,需要进行左旋、右旋操作*/if (node == father.getRight()){//左旋leftRotate(father);RedBlackNode temp = node;node = father;father = temp;}father.setBlack(true);grandFather.setBlack(false);rightRotate(grandFather);}else {RedBlackNode uncle = grandFather.getLeft();if (uncle != null && uncle.isBlack() == false){father.setBlack(true);uncle.setBlack(true);grandFather.setBlack(false);node = grandFather;continue;}if (node == father.getLeft()){rightRotate(father);RedBlackNode temp = node;node = father;father = temp;}father.setBlack(true);grandFather.setBlack(false);leftRotate(grandFather);}}root.setBlack(true);}public void leftRotate(RedBlackNode node){RedBlackNode right = node.getRight();RedBlackNode parent = node.getParent();if (parent == null){root = right;right.setParent(null);}else {if (parent.getLeft() != null && parent.getLeft() == node){parent.setLeft(right);}else {parent.setRight(right);}right.setParent(parent);}node.setParent(right);node.setRight(right.getLeft());if (right.getLeft() != null){right.getLeft().setParent(node);}right.setLeft(node);}private void rightRotate(RedBlackNode node){RedBlackNode left = node.getLeft();RedBlackNode parent = node.getParent();if (parent == null){root = left;left.setParent(null);}else {if (parent.getLeft() != null && parent.getLeft() == node){parent.setLeft(left);}else {parent.setRight(left);}left.setParent(left);}node.setParent(left);node.setLeft(left.getRight());if (left.getRight() != null){left.getRight().setParent(node);}left.setRight(node);}@Overridepublic void deleteNode(RedBlackNode root, RedBlackNode node) {}@Overridepublic void preOrder(List<Integer> showList, RedBlackNode node) {if(node == null) {return ;}//叶子if(node.getLeft() == null && node.getRight()==null){showList.add(node.getData());return ;}showList.add(node.getData());//递归 左孩子preOrder(showList, node.getLeft());//递归 右孩子preOrder(showList, node.getRight());}@Overridepublic void inOrder(List<Integer> showList, RedBlackNode node) {if(node == null) {return ;}//叶子if(node.getLeft() == null && node.getRight()==null){showList.add(node.getData());return ;}//递归 左孩子inOrder(showList, node.getLeft());showList.add(node.getData());//递归 右孩子inOrder(showList, node.getRight());}@Overridepublic void laOrder(List<Integer> showList, RedBlackNode node) {if(node == null) {return ;}//叶子if(node.getLeft() == null && node.getRight()==null){showList.add(node.getData());return ;}//递归 左孩子laOrder(showList, node.getLeft());//递归 右孩子laOrder(showList, node.getRight());showList.add(node.getData());}@Overridepublic void bfs(List<Integer> list, RedBlackNode node) {if (node == null){return;}LinkedList<RedBlackNode> queue = new LinkedList<>();queue.offer(node);while (!queue.isEmpty()){RedBlackNode child = queue.poll();list.add(child.data);if (child.left != null){queue.offer(child.left);}if (child.right != null){queue.offer(child.right);}}}
}

单元测试

package csdn.dreamzuora.tree;import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.Assertions;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;import static org.junit.Assert.*;/*** Title:* Description:** @version 1.0* @author: weijie* @date: 2020/10/22 14:31*/
public class RedBlackTreeTest {RedBlackTree RBtree = new RedBlackTree();@Beforepublic void init() {List<Integer> list = Arrays.asList(10, 5, 9, 3, 6, 7, 19, 32, 24, 17);RBtree.createTree(list);}@Testpublic void addNode(){}@Testpublic void deleteNode() {}@Testpublic void preOrder() {List<Integer> actualList = new ArrayList<>();RBtree.preOrder(actualList, RBtree.root);List<Integer> expectList = Arrays.asList(9, 5, 3, 6, 7, 19, 10, 17, 32, 24);Assertions.assertEquals(expectList, actualList);}@Testpublic void inOrder() {List<Integer> actualList = new ArrayList<>();RBtree.inOrder(actualList, RBtree.root);List<Integer> expectList = Arrays.asList(3, 5, 6, 7, 9, 10, 17, 19, 24, 32);Assertions.assertEquals(expectList, actualList);}@Testpublic void laOrder() {List<Integer> actualList = new ArrayList<>();RBtree.laOrder(actualList, RBtree.root);List<Integer> expectList = Arrays.asList(3, 7, 6, 5, 17, 10, 24, 32, 19, 9);Assertions.assertEquals(expectList, actualList);}@Testpublic void bfs() {List<Integer> actualList = new ArrayList<>();RBtree.bfs(actualList, RBtree.root);List<Integer> expectList = Arrays.asList(9, 5, 19, 3, 6, 10, 32, 7, 17, 24);Assertions.assertEquals(expectList, actualList);}@Testpublic void leftRotate(){}@Testpublic void rightRotate(){RedBlackNode node5 = new RedBlackNode(5);RedBlackNode node3 = new RedBlackNode(3);RedBlackNode node8 = new RedBlackNode(8);RedBlackNode node7 = new RedBlackNode(7);RedBlackNode node9 = new RedBlackNode(9);RBtree.root = node5;RBtree.root.left = node3;node8.left = node7;node8.right = node9;RBtree.root.right = node8;RBtree.leftRotate(RBtree.root);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/508816.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

冒泡排序、快速排序 java代码实现

文章目录冒泡排序源码实现单元测试优化快速排序源码实现单元测试冒泡排序 源码实现 package csdn.dreamzuora.sort;import java.util.List;/*** Title: 冒泡排序* Description:* 冒泡排序思想是把相邻的元素进行两两比较&#xff0c;当前面元素大于后面元素则进行交换* versi…

计数排序和桶排序 java代码实现

文章目录计数排序java代码实现单元测试桶排序java代码实现单元测试计数排序 java代码实现 package csdn.dreamzuora.sort;import java.util.List;/*** Title: 抽象出排序类* Description:** version 1.0* author: weijie* date: 2020/10/22 17:59*/ public abstract class So…

堆排序和归并排序 java代码实现

文章目录堆排序java代码实现单元测试归并排序java代码实现单元测试堆排序 java代码实现 package csdn.dreamzuora.sort;import java.util.List;/*** Title: 抽象出排序类* Description:** version 1.0* author: weijie* date: 2020/10/22 17:59*/ public abstract class Sort…

Hbase入门篇

HBase&#xff1a; 数据库&#xff1a;是一种面向列族存储的非关系型数据库用于存储结构化和非结构化数据&#xff1a;适用于单表非关系型数据的存储&#xff0c;不适合做关联查询&#xff0c;类似于JOIN等操作基于HDFS&#xff1a;数据持久化存储的体现形式是HFile&#xff0…

ElasticSearch入门篇

文章目录控制台RESTFULL操作REST风格说明基于REST命令说明&#xff1a;es支持的数据类型核心数据类型ik分词器使用ik_smart最少切分ik_max_word最细粒度索引操作索引库创建创建文档方式指定索引类型(以后这种方式会被弃用)不指定索引类型利用默认的_doc类型更新文档方式一&…

【待完成】并发包下常用到线程工具类汇总

文章目录并发容器BlockingQueueArrayBlockingQueueLinkedBlockingQueuePriorityBlockingDelayQueueSynchronousQueueBlockingDequeCopyOnWriteCopyOnWriteArrayListCopyOnWriteArraySetConcurrentLinkedQueue/DequeConcurrentHashMapConcurrentSkipListMap/Set同步工具类AQS实现…

判断对象属性值是否为空

private boolean checkObjFieldIsNotNull(Object obj){try {for (Field f : obj.getClass().getDeclaredFields()) {f.setAccessible(true);if (f.get(obj) ! null) {return true;}}}catch (IllegalAccessException e){}return false;}

爬虫中如何获取页面编码类型

获取页面的编码格式的三种方式&#xff1a; 根据Response中的header获取编码格式根据页面标签中的meta获取根据页面内容识别自动识别出编码格式&#xff0c;经过测试准确率比较高 三种方式可以结合使用&#xff0c;由于inputStream不能够被复用&#xff0c;但是inputStrem没有…

记录一次异常 java.lang.NoClassDefFoundError: org/apache/lucene/codecs/lucene53/Lucene53NormsFormat

异常信息&#xff1a; java.lang.NoClassDefFoundError: org/apache/lucene/codecs/lucene53/Lucene53NormsFormatat java.lang.Class.getDeclaredConstructors0(Native Method)at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)at java.lang.Class.getCon…

Spark集群部署与架构

在大数据时代&#xff0c;处理海量数据需要分布式计算框架。Apache Spark作为一种强大的大数据处理工具&#xff0c;可以在集群中高效运行&#xff0c;处理数十TB甚至PB级别的数据。本文将介绍如何构建和管理Spark集群&#xff0c;以满足大规模数据处理的需求。 Spark集群架构…

elasticsearch高级查询进阶

文章目录前期准备应用场景1.constant_score查询-不考虑文档频率得分&#xff0c;与搜索关键字命中更多的返回结果2.sort排序-分数相同情况下&#xff0c;按照指定价格域排序3.不考虑文档频率TF/IDF情况下&#xff0c;不同域打分权重不同进行召回4.不考虑文档频率TF/IDF情况下&a…

java核心技术-多线程并发设计原理以及常见面试题

文章目录写在前面多线程回顾Thread和Runnable面试官&#xff1a;为什么我们在项目中推荐使用使用Runnable方法而不用继承Thread&#xff1f;面试官&#xff1a;Callable为什么可以带返回值&#xff0c;你知道底层原理&#xff1f;面试题&#xff1a;线程了解&#xff1f;给我讲…

java核心技术-jvm基础知识

文章目录JVM回顾JVM、JRE、JDK之间关系&#xff1f;Java程序执行过程&#xff1f;面试官&#xff1a;解释执行和JIT(及时编译)两种执行方式有什么区别&#xff1f;java虚拟机内存管理jvm整体架构JVM只是定义内存划分规范等&#xff0c;具体实现依赖不同虚拟机实现&#xff0c;如…

阿里京东滴滴等大厂面试题汇总

文章目录11月面&#xff1a;京东一面【京东云与AI-协同办公】&#xff1a;京东一面现场面【京东云与AI-平台创新组】&#xff1a;京东二面&#xff1a;11月面&#xff1a;滴滴视频面【橙心优选】&#xff1a;11月面&#xff1a;国美零售【大数据-搜索组】8月面&#xff1a;阿里…

spring boot 如何动态替换bean?

替换Bean工具类 Component public class ApplicationContextUtil implements ApplicationContextAware {private static ApplicationContext applicationContext null;Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansExcept…

elasticsearch亿级数据量全量索引导入优化方案

Hbase scan读取时候&#xff0c;调大 hbase.client.scanner.timeout.period 超时时间,不然可能会跑异常 org.apache.hadoop.hbase.UnknownScannerException: org.apache.hadoop.hbase.UnknownScannerException: Unknown scanner 479187903508737326. This can happen due to an…

多线程场景下利用ThreadLocal是线程安全?

文章目录背景多线程场景测试代码结论背景 ThreadLocal原理以及基本概念这里我就不介绍了&#xff0c;这里我们主要关注ThreadLocal是否是线程安全吗&#xff1f;其实如果我们知道ThreadLocal原理我们肯定知道它是线程安全的&#xff0c;但是我在开发的时候不放心做了个测试&am…

记录一次服务进程强行退出的问题排查过程

场景&#xff1a;我这边从Hbase跑一亿多的全量数据录入Elasticsearch中&#xff0c;跑了四个多小时&#xff0c;程序突然挂掉了&#xff0c;然后我就纳闷了&#xff0c;为啥突然挂掉了&#xff1f;&#xff1f;&#xff1f; 思路1:是不是Java 进程抛出OOM异常&#xff1f; 分析…

No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK

文章目录问题背景&#xff1a;问题排查过程拓展问题背景&#xff1a; 运行环境&#xff1a;Mac For IDEA 我的Mac 更新最新系统(window解决办法也是如下)后&#xff0c;由于新系统的Mac会带JDK导致自动更新Java版本&#xff0c;最后导致我在Idea控制台中执行mvn install后抛出…

ElasticSearch聚合查询

文章目录聚合分组求和平均值分析每种颜色下每种品牌的平均价格更多的metric学习Cardinality(唯一值)查询聚合分析查询聚合全局聚合 深入聚合数据分析_global bucket&#xff1a;单个品牌与所有品牌销量对比过滤聚合&#xff1a;统计价格大于1200的电视平均价格统计最近一个月的…