数据结构—红黑树和二叉搜索树
一、树
1. 红黑树与二叉搜索树
1.1 二叉搜索树
1.2.1 定义
-
如果左子树不为空,则左子树所有结点值都小于根节点的值; 如果右子树不为空,则右子树所有节点值都大于或等于根节点的值; 任意一颗字数也是二叉搜索树。 查找时间复杂度是O(logn),极端降低到O(n)。
1.2.2 平衡二叉搜索树(AVL树)
1. 平衡树(Balance Tree,BT)
-
任意结点的子树的高度差都小于等于1; 常见的平衡树包括B树(MySQL中的索引)、AVL树等
2. 平衡二叉搜索树-AVL树
-
同时满足二叉搜索树以及平衡树的特点; 可以有效的减少二叉树的深度,从而提高了查询的效率; 严格平衡,代价高。
1.2 红黑树(Red Black Tree, R-B tree)
1.2.1 定义
-
一种特化的AVL树,在插入和删除时通过特定操作(左旋或右旋)保持二叉查找是的相对平衡,从而获得较高的查找性能。 不是一种严格的AVL树,只是黑色平衡 左子树和右子树的黑色结点数量相等
1.2.2 红黑树特性->黑跟黑叶红不邻,同祖等高只数黑
首先,符合二叉搜索树;
- 结点非黑即红;
- 根节点是黑色;
- 叶子结点是黑色的;
- 相邻节点不同为为红色,红色结点的子节点必须是黑色;
- 从一个节点到该节点的叶子节点的所有路径上包含的黑节点数量相等。
1.2.3 红黑树查找结点
-
选择根节点作为当前结点 按照二叉搜索树特点进行循环查找 若值与当前节点值相等,返回该节点; 若值小于当前节点,左孩子作为当前节点; 否则,右节点作为当前节点。 未找到返回nil
//利用树的特点-递归 func(root *TreeNode) findrbtreenode(value int) *TreeNode { var dfs func(node *TreeNode)*TreeNode dfs = func(node *TreeNode)*TreeNode { var result *TreeNode if root != nil { if root.Val == value { return root }else if root.Val > value{ result = dfs(root.Left) }else{ result = dfs(root.Right) } } return result } return dfs(root) } //迭代法 func(root *TreeNode)find(value int)*TreeNode { for root!=nil { if root.Val==value { return root }else if root.Val < value{ root = root.Right }else { root = root.Left } } return nil }
1.2.4 左旋与右旋
镜像情况,互补旋转。 左旋:左旋左不变,与右互换放左边,右由右左来补全。 左旋是以某个结点作为旋转结点,其右子结点变为旋转结点的父节点,右子结点的左子结点变为旋转结点的右子结点,左子结点保持不变。 右旋:右旋右不变,与左互换放右边,左由左右来补全。 右旋是以某个结点作为旋转结点,其左子结点变为旋转结点的父节点,左子结点的右子结点变为旋转结点的左子结点,右子结点保持不变。
1.2.5 红黑树复杂度分析
- 一棵含有n个结点的红黑树的高度之多为2log(n+1)
- 查找时间复杂度:O(logn)
- 插入时间复杂度:最多两次旋转,O(1)+O(logn)
- 删除时间复杂度:最多三次旋转,O(1)+O(logn)
- 空间复杂度:O(n)
1.2.6 AVL vs 红黑树
-
插入:AVL和红黑树都是最多两次旋转实现复衡,旋转的量级是O(1) 删除:AVL旋转的量级为O(logN),红黑树最多旋转3次,实现复衡只需要O(1) 红黑树复衡效率更高,AVL的查找效率更高;红黑树删除更高效; 红黑树较低成本的解决方法,是对查找、插入、删除效率的折中。