从二分法开始
给定一个1-100的数字,让你来猜,会根据你给我的数字
我来告诉你这个数字是大了还是小了 很明显这就用二分
来猜
除了运气这就是最快的解决方案
假设 result :75
第一步 :50:(min+max)/2 = (1+100)/2= 50 小了
第二步 :75:(min+max) /2 = (50+100) /2 = 75 对了
时间复杂度:logn
这个过程用数据结构来分析的话二分法和二叉搜索树其实差不多
二叉查找/排序/搜索树
- 如果他的左子树不为空,则左子树上节点的值都小于根节点
- 如果他的右子树不为空,则右子树上节点的值都大于根节点
- 子树同样也要遵循以上两点
- 如果他是一个二叉查找/排序/搜索树那么他的中序遍历一定是有序的
时间复杂度分析
时间复杂度就是这棵树的深度 h
n是总节点数 h为二叉树的深度
则我们可以列出式子 n = (2^h) - 1
所以可以得到 h = log2(n+1)
就先这样就满足一颗搜索二叉树的所有条件那么这棵树需要多少的步才能找到5呢
- 5<6 向6的左边走 res = tree.left
- 5>3 向3的右边走 res = res.right
- 找到5
但是到这里就发现了一个问题
只要这个二叉搜索树足够糟糕那么他就会变成一个列表
就像这样一颗仔细分析确实如果他的右子树不为空,则右子树上节点的值都大于根节点但是我要查找一个数字的时间复杂度 :深度 = 节点数时间复杂度:n
所以这个树的最差情况回到了暴力破解的一样的时间复杂度违背了使用它的最开始的初衷
所以开发者们引入了一个概念:平衡二叉查找树
平衡二叉树-红黑树(自动平衡的二叉查找树)
链表 ->二叉树 ->二叉查找树 ->特殊的二叉查找树
- 每个节点不是红色就是黑色
- 两个红色节点都不能连在一起
- 根节点都是黑色
- 每个红色节点的两个子节点都是黑色,叶子节点都是黑色
上图的节点下都有null节点才是最终的叶子节点
为了保证他的性质所以就需要一些操作来满足他的性质
- 改变颜色 红色变黑色 黑色变红色
- 旋转 左旋 右旋
变色顾名思义就是可以给结点变颜色来保证他的性质(具体什么时候用到下面会写)
红黑树的左旋右旋是怎样的呢
首先假设有这样一棵红黑树
这棵树的左旋操作是怎么做的呢
左旋就是把选中的节点的右子树的的左子树变为当前选择的结点之后之前选择点的右子树(也就是8这个结点)的左子树是不是变为了当前选择的点,那么他的右子树就应该放到之前选择的点(也就是5这个节点)
转换后
右旋就像是一个左旋的镜面翻转
一开始是这样
选中结点是8这个结点然后5结点的右子树变成8,原来5结点上的右子树放到8的左子树上这样就完成了右旋
那么在红黑树中什么时候需要左旋什么时候右旋什么时候变颜色呢
首先要了解概念,所有插入的结点都是红色,如果可以插入黑色结点的话那我们一直插入黑色结点那么不管怎么样都会符合红黑树的规矩,所以一定是红色的
- 变颜色情况
当前节点的父结点是红色,而且他的祖父节点(父结点的父结点)的另一个结点(叔叔结点)也是红色
那么1.把父结点和叔叔结点变为黑色2.把祖父结点设为红色3.然后把指针定义到祖父结点设为当前要操作的结点分析变换规则
①左旋:当前父亲结点是共色叔叔结点是黑色的时候,且当前结点是右子树。以父亲结点左旋
②右旋:当前父亲结点是共色叔叔结点是黑色的时候,且当前结点是左子树。右旋
把父亲结点变为黑色把祖父结点变为红色,以祖父结点右旋
比如上面写的这个给红黑树为例子如果我要插入一个37会插入到哪里呢
这个37的插入符合二叉搜索树的性质从根结点进行判定小于向左走那么路线就是左右左左到上图这个位置
这个时候就发现这个37结点和父节点同为红色且叔叔结点是红色所以满足第一种变颜色的情况所以就开始变颜色
则这棵树会变成这个样子,这个时候指针那个放在了37结点的祖父结点45上,这个时候发现45和他的父节点同为红色所以需要改变他的父亲结点是红色叔叔结点是黑色他45结点又是右子树所以就满足左旋条件以45结点的父节点37开始左旋
然后做完上一步操作35和他的父亲结点还是同为红色但是他这个时候已经变成了左子树,所以就是用第三个右旋的方法来旋转
(②右旋:当前父亲结点是共色叔叔结点是黑色的时候,且当前结点是左子树。右旋
把父亲结点变为黑色把祖父结点变为红色,以祖父结点右旋)
一系列操纵过后这棵树就自动平衡成了这样一颗优美的红黑树
下次会和大家分享删除算法以及红黑树的源码分析
参考链接:https://www.bilibili.com/video/BV1tE411f7tP?from=search&seid=18355378427236505690