一、AVL树
不同搜索的对比:1.暴力搜索时间复杂度是O(N);2.二分查找的时间复杂度是O(lgN),但是伴随着有序,插入删除挪动数据的成本极高;3.二叉搜索的时间复杂度是高度次数,极端场景会退化为类似链表时间复杂度是O(N)/O(lgN);4.平衡二叉搜索树;5.多叉平衡搜素树;6.哈希表快速搜索;
平衡二叉搜索树有avl树和红黑树;
1.1概念
AVL树又叫做高度平衡二叉搜索树;
二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右子树高度之差的绝对值不超过 1( 需要对树中的结点进行调整 ),即可降低树的高度,从而减少平均搜索长度。
AVL树要不是空树,要不然就是:1.左右子树都是AVL树,平衡因子(右子树高度减去左子树高度)的绝对值小于等于1;
满二叉树就是最平衡的AVL树;
1.2AVL树的模拟实现
1.2.1插入原理
先创建搜索二叉树,然后更新平衡因子,然后解决平衡错误(旋转解决);
1.左子树插入会使得父亲的平衡因子–,右子树会使得父亲的平衡因子++,平衡因子只会影响祖先;
2.平衡因子变为0,说明树的高度没有发生变化,其他祖先的平衡因子不需要发生变化,变为正负一才需要,沿着祖先路径,parent和cur向上调整;
3.插入一个节点是平衡因子默认就是0;
4.若平衡因子是2或者-2,就不平衡了,需要旋转,旋转要注意:1.保持子树是搜索树;2.变成平衡树且降低整棵树的高度;即左单旋,对于右子树过高,向左旋转,使得parent->right=cur->left,cur->left=parent,强行让parent 节点向下走一截,旋转之后的高度相较于插入之前是没有变化的。在旋转的过程中除了更新平衡因子,还需要更新parent_。右单旋类似;
5更新到平衡因子为0或者旋转结束或者更新到根节点就插入结束;
旋转原理:插入前平衡因子是1/-1;
h是子树的高度,h是1或者0和之前是一样的,如果h是2,则a、b子树可以是:
但是c只能是第三种,因为第1和第2种都不会影响到30和60节点的平衡因子;一共有36种可能的插入情况。即无法穷尽,但是核心规则是不变的。
双旋
当parent与cur的平衡因子为异号时,即是折线就是双旋,否则就是直线单旋;
右左双旋:
h=0,就是简单的直线;h=1,就是在60的左右叶子节点插入都会使得parent异常;h=2,a和d可以是上述任意三种情况,bc是一个节点。
先90为旋转点进行右旋,然后30为旋转点进行左旋。即第一次旋转变成直线,左单旋,第二次单旋变成平衡。要注意双旋之后要更新平衡因子。
观察发现双旋的结果本质就是60的左给30,右给90并且30,90,做了60的左右。
更新平衡因子分三种情况,1、插入元素后,对于30、60、90,60的平衡因子为-1,说明在60的左子树插入,最终会使得60的右的平衡因子为1,其他为0;2、60平衡因子为1,则60左的平衡因子为-1;3、60的平衡因子为0,则60左右的平衡因子为0。
但是双旋存在问题。学会使用自己写一个辅助程序帮助调试。对于循环可以if等于具体的值来打断点调试。
#pragma once#include <cassert>namespace AvlTree
{template <class K, class V>struct AVLTreeNode{// 构造函数AVLTreeNode(const pair<K, V> kv) : kv_(kv), left_(nullptr), right_(nullptr), parent_(nullptr), bf_(0) {}// 成员pair<K, V> kv_;AVLTreeNode<K, V> *left_;AVLTreeNode<K, V> *right_;AVLTreeNode<K, V> *parent_; // 三叉链便于旋转// 平衡因子int bf_;};template <class K, class V>class AVLTree{// 内嵌类型typedef AVLTreeNode<K, V> node;public:// 默认构造函数AVLTree() : root_(nullptr) {}public:// 普通成员函数void rotatel(node *parent);void rotater(node *parent);void rotaterl(node *parent);void rotatelr(node *parent);bool insert(const pair<K, V> &kv);int height(node *root);bool isavltree(){return _isavltree(root_);}void inorder(){_inorder(root_);}private:// 私有成员void _inorder(node *root);bool _isavltree(node *root);node *root_;};template <class K, class V>void AVLTree<K, V>::rotatel(node *parent){node *cur = parent->right_;node *curleft = cur->left_;parent->right_ = curleft;node *ppnode = parent->parent_;if (curleft)curleft->parent_ = parent;parent->parent_ = cur;cur->left_ = parent;parent->bf_ = 0;cur->bf_ = 0;if (parent == root_){root_ = cur;cur->parent_ = nullptr;}else{if (ppnode->left_ == parent){ppnode->left_ = cur;}else{ppnode->right_ = cur;}cur->parent_ = ppnode;}}template <class K, class V>void AVLTree<K, V>::rotater(node *parent){node *cur = parent->left_;node *curright = cur->right_;node *ppnode = parent->parent_;parent->left_ = curright;cur->right_ = parent;if (curright)curright->parent_ = parent;parent->parent_ = cur;parent->bf_ = 0;cur->bf_ = 0;if (parent == root_){root_ = cur;cur->parent_ = nullptr;}else{if (ppnode->left_ == parent){ppnode->left_ = cur;}else{ppnode->right_ = cur;}cur->parent_ = ppnode;}}template <class K, class V>void AVLTree<K, V>::rotaterl(node *parent){// 更新平衡因子node *cur = parent->right_;node *curleft = cur->left_;int bf = curleft->bf_;rotater(parent->right_);rotatel(parent);if (bf == 0){cur->bf_ = 0;curleft->bf_ = 0;parent->bf_ = 0;}else if (bf == -1){cur->bf_ = 1;curleft->bf_ = 0;parent->bf_ = 0;}else if (bf == 1){parent->bf_ = -1;cur->bf_ = 0;curleft->bf_ = 0;}else{assert(false);}}template <class K, class V>void AVLTree<K, V>::rotatelr(node *parent){// 更新平衡因子node *cur = parent->left_;node *curright = cur->right_;int bf = curright->bf_;rotatel(parent->left_);rotater(parent);if (bf == 0){cur->bf_ = 0;curright->bf_ = 0;parent->bf_ = 0;}else if (bf == -1){cur->bf_ = 0;curright->bf_ = 0;parent->bf_ = 1;}else if (bf == 1){parent->bf_ = 0;cur->bf_ = -1;curright->bf_ = 0;}else{assert(false);}}template <class K, class V>bool AVLTree<K, V>::insert(const pair<K, V> &kv){if (root_ == nullptr){root_ = new node(kv);return true;}node *cur = root_;node *parent = cur;while (cur){if (kv.first > cur->kv_.first){parent = cur;cur = cur->right_;}else if (kv.first < cur->kv_.first){parent = cur;cur = cur->left_;}else{return false;}}cur = new node(kv);if (kv.first > parent->kv_.first){parent->right_ = cur;}else{parent->left_ = cur;}cur->parent_ = parent;// 控制平衡,更新平衡因子while (parent){if (cur == parent->left_){parent->bf_--;}else{parent->bf_++;}if (!parent->bf_){break;}if (parent->bf_ == 1 || parent->bf_ == -1){cur = parent;parent = parent->parent_;}else if (parent->bf_ == 2 || parent->bf_ == -2){if (parent->bf_ == 2 && cur->bf_ == 1){// 左单旋rotatel(parent);break;}else if (parent->bf_ == -2 && cur->bf_ == -1){// 右单旋rotater(parent);break;}else if (parent->bf_ == 2 && cur->bf_ == -1){// 右左双旋rotaterl(parent);break;}else if (parent->bf_ == -2 && cur->bf_ == 1){// 左右双旋rotatelr(parent);break;}else{assert(false);}}else{assert(parent->bf_ <= 2 && parent->bf_ >= -2);}}return true;}template <class K, class V>int AVLTree<K, V>::height(node *root){if (root == nullptr){return 0;}int leftheight = height(root->left_);int rightheight = height(root->right_);return leftheight > rightheight ? leftheight + 1 : rightheight + 1;}template <class K, class V>bool AVLTree<K, V>::_isavltree(node *root){if (root == nullptr){return true;}int leftheight = height(root->left_);int rightheight = height(root->right_);if ((rightheight - leftheight) != root->bf_){cout << "平衡因子异常:" << root->kv_.first << ":" << root->kv_.second << ":" << root->bf_ << endl;return false;}return abs(rightheight - leftheight) < 2 && _isavltree(root->left_) && _isavltree(root->right_);}template <class K, class V>void AVLTree<K, V>::_inorder(node *root){if (root == nullptr){return;}_inorder(root->left_);cout << root->kv_.first << ":" << root->kv_.second << endl;_inorder(root->right_);}
}