数据结构--红黑树
来源:互联网 发布:淘宝达人电脑端入口 编辑:程序博客网 时间:2024/06/05 00:18
1、基本概念
红黑树是二叉查找树的一种,与平衡查找树类似,但红黑树的平衡性不像平衡树那样严格。
红黑树的特点:
- 任何一个节点都有颜色,黑色或者红色
- 根节点是黑色的
- 父子节点之间不能出现两个连续的红节点
- 任何一个节点向下遍历到其子孙的叶子节点,所经过的黑节点个数必须相等
- 空节点被认为是黑色的
红黑树的基本操作插入、删除、遍历。内容操作和平衡树一样,左右旋转。
public class Test { private static Node root; private static final boolean RED = false; private static final boolean BLACK = true; static class Node{ int data; Node left; Node right; Node parent; boolean color; public Node(int data) { this.data = data; this.color = BLACK; } } public static void main(String[] args) { int[] src = { 10, 40, 30, 60, 90, 70, 20, 50, 80 }; for (int i = 0; i < src.length; i++) insert(src[i]); midTrav(root); System.out.println("\n-----------------------------------"); Node node = searchNode(root, 30); System.out.println(node.data+""); remove(node); midTrav(root); System.out.println("\n-----------------------------------"); } /* * px px * / / * x y * / \ --(左旋)-. / \ * lx y x ry * / \ / \ * ly ry lx ly * */ private static void leftRotate(Node x) { Node y = x.right; // 将 “y的左孩子” 设为 “x的右孩子”; x.right = y.left; if(y.left != null) //将ly的父节点指向x y.left.parent = x; //将y的父节点指向px y.parent = x.parent; //为y指定父节点 if(x.parent == null) root = y;//x的父节点为空 表示x为根节点 else //如果x为左子树,则让y也为左子树 if(x.parent.left == x) y.parent.left = y; else //如果x为右子树,则让y也为右子树 y.parent.right = y; //将x的父节点指向y y.left = x; x.parent = y; } /* * 对红黑树的节点(y)进行右旋转 * * 右旋示意图(对节点y进行左旋): * py py * / / * y x * / \ --(右旋)-. / \ * x ry lx y * / \ / \ * lx rx rx ry * */ private static void rightRotate(Node y) { Node x = y.left; y.left = x.right; if (x.right != null) x.right.parent = y; x.parent = y.parent; if (y.parent == null) { root = x; } else { if (y == y.parent.right) y.parent.right = x; else y.parent.left = x; } x.right = y; y.parent = x; } private static void remove(Node node) { Node child, parent; boolean color; // 被删除节点的"左右孩子都不为空"的情况。 if ( (node.left!=null) && (node.right!=null) ) { // 被删节点的后继节点。(称为"取代节点") // 用它来取代"被删节点"的位置,然后再将"被删节点"去掉。 Node replace = node; // 获取后继节点 replace = replace.right; while (replace.left != null) replace = replace.left; // "node节点"不是根节点(只有根节点不存在父节点) if (node.parent!=null) { if (node.parent.left == node) node.parent.left = replace; else node.parent.right = replace; } else { // "node节点"是根节点,更新根节点。 root = replace; } // child是"取代节点"的右孩子,也是需要"调整的节点"。 // "取代节点"肯定不存在左孩子!因为它是一个后继节点。 child = replace.right; parent = replace.parent; // 保存"取代节点"的颜色 color = replace.color; // "被删除节点"是"它的后继节点的父节点" if (parent == node) { parent = replace; } else { // child不为空 if (child!=null) child.parent = parent; parent.left = child; replace.right = node.right; node.right.parent = replace; } replace.parent = node.parent; replace.color = node.color; replace.left = node.left; node.left.parent = replace; if (color == BLACK) removeFixUp(child, parent); node = null; return ; } if (node.left !=null) { child = node.left; } else { child = node.right; } parent = node.parent; // 保存"取代节点"的颜色 color = node.color; if (child!=null) child.parent = parent; // "node节点"不是根节点 if (parent!=null) { if (parent.left == node) parent.left = child; else parent.right = child; } else { root = child; } if (color == BLACK) removeFixUp(child, parent); node = null; } private static void removeFixUp(Node node, Node parent) { Node other; while ((node==null || node.color==BLACK) && (node != root)) { if (parent.left == node) { other = parent.right; if (other.color == RED) { // Case 1: x的兄弟w是红色的 other.color = BLACK; parent.color = RED; leftRotate(parent); other = parent.right; } if ((other.left==null || other.left.color==BLACK) && (other.right==null || other.right.color==BLACK)) { // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的 other.color = RED; node = parent; parent = node.parent; } else { if (other.right==null || other.right.color==BLACK) { // Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。 other.left.color = BLACK; other.color = RED; rightRotate(other); other = parent.right; } // Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。 other.color = parent.color; parent.color = BLACK; other.right.color = BLACK; leftRotate(parent); node = root; break; } } else { other = parent.left; if (other.color == RED) { // Case 1: x的兄弟w是红色的 other.color = BLACK; parent.color = RED; rightRotate(parent); other = parent.left; } if ((other.left==null || other.left.color==BLACK) && (other.right==null || other.right.color==BLACK)) { // Case 2: x的兄弟w是黑色,且w的俩个孩子也都是黑色的 other.color = RED; node = parent; parent = node.parent; } else { if (other.left==null || other.left.color==BLACK) { // Case 3: x的兄弟w是黑色的,并且w的左孩子是红色,右孩子为黑色。 other.right.color = BLACK; other.color = RED; leftRotate(other); other = parent.left; } // Case 4: x的兄弟w是黑色的;并且w的右孩子是红色的,左孩子任意颜色。 other.color = parent.color; parent.color = BLACK; other.left.color = BLACK; rightRotate(parent); node = root; break; } } } if (node!=null) node.color = BLACK; } //插入操作 public static void insert(int data){ Node y = null; Node x = root; //找到叶子节点 while(x != null) { y = x; if(data > x.data) x = x.right; else if(data < x.data) x = x.left; else return; } //插入 Node node = new Node(data); node.parent = y; if(y == null) root = node; else if(node.data > y.data) y.right = node; else y.left = node; node.color = RED; //修正红黑树 insertFixUp(node); } private static void insertFixUp(Node node) { Node parent, gparent; while ((parent=node.parent)!=null && parent.color==RED) { gparent = parent.parent; //一、若“父节点”是“祖父节点的左孩子” if(parent == gparent.left) { // Case 1条件:父节点和叔叔节点是红色 则父节点、叔叔节点都为黑,祖父节点为红 Node uncle = gparent.right; if ((uncle!=null) && uncle.color==RED) { uncle.color = BLACK; parent.color = BLACK; gparent.color = RED; node = gparent; continue; } // Case 2条件:叔叔是黑色,且当前节点是右孩子,进行左转换 if (parent.right == node) { Node tmp; leftRotate(parent); tmp = parent; parent = node; node = tmp; } // Case 3条件:叔叔是黑色,且当前节点是左孩子。将父节点为根的子树右旋转 parent.color = BLACK; gparent.color = RED; rightRotate(gparent); } else { //二、若“z的父节点”是“z的祖父节点的右孩子” // Case 1条件:叔叔节点是红色 Node uncle = gparent.left; if ((uncle!=null) && uncle.color==RED) { uncle.color = BLACK; parent.color = BLACK; gparent.color = RED; node = gparent; continue; } // Case 2条件:叔叔是黑色,且当前节点是左孩子 if (parent.left == node) { Node tmp; rightRotate(parent); tmp = parent; parent = node; node = tmp; } // Case 3条件:叔叔是黑色,且当前节点是右孩子。 parent.color = BLACK; gparent.color = RED; leftRotate(gparent); } } root.color = BLACK; } //中序遍历 public static void midTrav(Node node){ if(node == null) return; midTrav(node.left); System.out.print(node.data + " "); midTrav(node.right); } //查找 public static Node searchNode(Node node, int data){ while(node != null) if(data > node.data) node = node.right; else if(data < node.data) node = node.left; else return node; return node; }}
如果需要存储多个相同数据,Node中可以添加一个count字段,存放数量
参考:
http://www.cnblogs.com/skywang12345/p/3624343.html
http://blog.csdn.net/tcorpion/article/details/54968644
阅读全文
0 0
- 数据结构红黑树
- 数据结构:红黑树
- [数据结构]红黑树
- 数据结构-红黑树
- 数据结构-红黑树
- 【数据结构】红黑树
- 数据结构 - 红黑树
- 数据结构--红黑树
- 【数据结构】红黑树
- 【数据结构】红黑树
- 【数据结构】红黑树
- 数据结构---------红黑树
- 数据结构 红黑树
- 数据结构-红黑树
- 【数据结构】红黑树
- 数据结构--红黑树
- 数据结构--红黑树
- 数据结构-红黑树
- Android Activity
- Ceph vs Gluster之开源存储力量的较量
- 关于Linux环境下安装配置vsftpd服务全攻略(踩坑)
- Plugin execution not covered by lifecycle configuration
- 查找
- 数据结构--红黑树
- 设计模式(JAVA版):1.简单工厂模式
- A
- SVN和git
- Xamarin.Forms 用户界面——控件——Styles
- C++笔录
- qt拼图游戏
- 数字反转
- 敏捷结果30天之第一天:总体认识敏捷结果方法