博客写的代码都放在这里:gitee仓库链接
1.二叉搜索树
1.1.基本概念
二叉搜索树又称二叉排序树,可以为空,如果不为空具有以下性质的二叉树
:
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也都为二叉搜索树
1.2.二叉搜索树的结点结构
struct TreeNode
{
TreeNode<T>* _left;
TreeNode<T>* _right;
T _key;
TreeNode(T key)
:_left(nullptr)
, _right(nullptr)
, _key(key)
{}
};
1.3二叉搜索树的代码实现
1.二叉搜索树的插入
实现思路:
- 如果树为空,直接插入节点
- 如果树不为空,找到待插入位置(cur)的父节点(parent)
- 判断待插入的节点(cur)的值是否小于或大于父节点(parent)的值,插入对应的左边或右边
bool Insert(const T& key)
2.二叉搜索树的删除
实现思路:
删除的节点有两大类:1.没有子树或者只有一颗子树 2.有两颗子树
第一类的解决方式是:找到当前待删除的节点和其父节点,然后直接让父节点指向带待删除结点的子树(左子树和右子树)
- 把NULL也看成是一个特殊结点(最好的认识!)
- 分别删除4和14,让parent指向cur的子树(左或右,说明这里就需要判断了);这里4的子树都是NULL,但是这里看成左子树和右子树都是可以的(只是我习惯从左往右)
第二类的解决方法是:使用替换法
- 找到一个结点和当前结点进行交换,怎么找一个符合的结点呢?将当前节点(cur)和左子树的最大节点(最右节点)或者右子树最小节点(最左节点)进行替换。
- 如这里删除3和8,找到leftMax说明已经是最右边的结点了!就让parent指向leftMax的左子树
bool Erase(const T& key);
1.4.二叉搜索树的性能
当二叉搜索树为完全二叉树,或者接近完成二叉树的时,它的插入或者说查找效率时log2(N),但是但插入的数据有序或或者接近有序,那么就会退化成O(N)。
所以,为了解决退化问题,可以使用平衡二叉树的红黑树来解决!
2.平衡二叉树
二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查
找元素相当于在顺序表中搜索元素,效率低下。
当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度,搜索时间复杂度O(log2N)
平衡因子(bf) = 右子树的高度 - 左子树的高度
2.1平衡二叉树结点的定义
struct AVLTreeNode
{
std::pair<K, V> _kv;
AVLTreeNode<K,V>* _left;
AVLTreeNode<K,V>* _right;
AVLTreeNode<K,V>* _parent;
int _bf;
AVLTreeNode(const std::pair<K, V> kv)
:_kv(kv)
, _left(nullptr)
, _right(nullptr)
, _parent(nullptr)
, _bf(0)
{}
};
2.2.平衡二叉树代码实现
1.插入结点
bool insert(const std::pair<K, V>& kv)
实现思路分为两步:
- 按照二叉搜索树的方式插入新节点
- 调整节点的平衡因子(不平衡是通过旋转来平衡,将调整平衡的树的平衡因子作修改)
2.判断是否是平衡二叉树
bool banlan(){}
2.3.平衡二叉树的旋转
- 左单旋
- 根据二叉搜索树的方法,将结点88插入45的右子树,插入成功;成功之后要修改 ? 平衡因子,并判断是否要调整平衡!
- 当parent == 0时说明完全平衡,不用调整;等parent的绝对值为1时,有一侧偏高了,需要往上找上祖先;当parent的绝对值是,就需要平衡以parent为根的树(或子树)!
需要左旋转,调整平衡!
步骤:
- 将cur的左子树,作为parent的右子树;将parent作为cur的左子树
- 修改移动节点的_parent指向关系
- 修改parent和cur的平衡因子,都修改成0
**一般情况:**上面是左单旋的其中一个例子,实际上随着层数的增高,左边旋的情况,无穷无尽,但是旋转的步骤都是一样的,来分析一下:
可以不同的数对高度h代入,得到不同情况的树。
- 右单旋
注意参考,左单旋!
- 左右双旋
注意参考,右左选旋!
- 右左双旋
- 先以100为节点做右单旋,再以50为节点做左单旋
- 调整平衡因子,怎么调整呢,分为三种情况:
上面的两种情况都是h > 0的情况,我们来看看h = 0的情况是怎么样的
通过三种情况发现,双旋后的平衡因子调整和60的平衡因子相关。
2.4.平衡二叉树的性能
AVL树是一棵绝对平衡的二叉搜索树,其要求每个节点的左右子树高度差的绝对值都不超过1,这样就可以保证高效的查找(O(log2(N)))。但是如果要对AVL树做一些结构修改的操作,性能非常低下,比如:插入时要维护其绝对平衡,旋转的次数比较多,更差的是在删除时,有可能一直要让旋转持续到根的位置。文章来源:https://www.toymoban.com/news/detail-819014.html
因此:如果需要一种查询高效且有序的数据结构,而且数据的个数为静态的(即不会改变),可以考虑AVL树,但一个结构经常修改,就不太适合。文章来源地址https://www.toymoban.com/news/detail-819014.html
到了这里,关于数据结构:搜索二叉树 | 平衡二叉树的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!