平衡搜索树---AVL树
2016-10-30 10:50
405 查看
AVL树是一种高度平衡的二叉搜索树,它的每个结点都有一个平衡因子,这个平衡因子的取值是-1,0,1(平衡因子 = 右子树高度 - 左子树高度)
AVL树具有的性质:
1.左子树和右子树的高度差不超过1;
2.树中的各子树都是AVL树
一、AVL树结点的定义
为了判断每个子树是否平衡,因此在定义AVL树的结点的时候就应该在搜索二叉树的基础上加一个平衡因子_bf
①当插入结点的key与某个结点的_key相等时,插入失败,返回false;
②每插入一个结点,就应该检查是否平衡,判断的依据就是_bf的值不超过1
a.当插入一个结点后,父亲结点的_bf由-1/1变为0,说明在插入之前父亲节点有一个子树,此时整棵树的高度不变
b.当插入一个结点后,父亲结点的_bf由0变为-1/1,说明在插入之前父亲节点没有子树,此时整棵树的高度一定变
如上图所示的这种情况插入一个结点后整棵树仍然保持平衡的,但如果此时以cur作为父亲节点,插入一个结点后还会平衡嘛?!
此时的ppNode的平衡因子已经变为-2,显然已经不满足AVL树的性质。为了解决这种情况,就要对树进行旋转,以达到平衡。
(PS:我对旋转这块的内容写了一篇博客,在这里就不写了,详情请戳这里>>平衡搜索树中的左单旋&右单旋&双旋)
插入的几种情况总结起来就是:
当parent->_bf变为0,就停止更新(平衡因子);当parent->_bf变为-1/1,继续向上更新平衡因子;当parent->_bf变为-2/2,进行旋转
假设一棵AVL树有N个结点,那么它的高度可以保持在lgN(log以2为底的N的对数),
插入时最好的情况就是第一次就能找到这个结点的位置进行插入,时间复杂度为O(1);最坏的情况是需要遍历整棵树的高度次,时间复杂度为O(lgN)
AVL树具有的性质:
1.左子树和右子树的高度差不超过1;
2.树中的各子树都是AVL树
一、AVL树结点的定义
为了判断每个子树是否平衡,因此在定义AVL树的结点的时候就应该在搜索二叉树的基础上加一个平衡因子_bf
template<class K,class V> struct AVLTreeNode { AVLTreeNode(const K& key,const V& value) :_left(NULL) ,_right(NULL) ,_parent(NULL) ,_key(key) ,_value(value) ,_bf(0) {} AVLTreeNode<K,V>* _left; AVLTreeNode<K,V>* _right; AVLTreeNode<K,V>* _parent; K _key; V _value; int _bf; //平衡因子 };二、AVL树的操作---插入
①当插入结点的key与某个结点的_key相等时,插入失败,返回false;
②每插入一个结点,就应该检查是否平衡,判断的依据就是_bf的值不超过1
a.当插入一个结点后,父亲结点的_bf由-1/1变为0,说明在插入之前父亲节点有一个子树,此时整棵树的高度不变
b.当插入一个结点后,父亲结点的_bf由0变为-1/1,说明在插入之前父亲节点没有子树,此时整棵树的高度一定变
如上图所示的这种情况插入一个结点后整棵树仍然保持平衡的,但如果此时以cur作为父亲节点,插入一个结点后还会平衡嘛?!
此时的ppNode的平衡因子已经变为-2,显然已经不满足AVL树的性质。为了解决这种情况,就要对树进行旋转,以达到平衡。
(PS:我对旋转这块的内容写了一篇博客,在这里就不写了,详情请戳这里>>平衡搜索树中的左单旋&右单旋&双旋)
插入的几种情况总结起来就是:
当parent->_bf变为0,就停止更新(平衡因子);当parent->_bf变为-1/1,继续向上更新平衡因子;当parent->_bf变为-2/2,进行旋转
bool Insert(const K& key, const V& value) { if (_root == NULL) { _root = new Node(key,value); return true; } Node* cur = _root; Node* parent = NULL; while (cur) { if (cur->_key > key) { parent = cur; cur = cur->_left; } else if(cur->_key < key) { parent = cur; cur = cur->_right; } else { //已经有key,插入失败 return false; } } cur = new Node(key,value); cur->_parent = parent; if (cur->_key < parent->_key) { parent->_left = cur; } else { parent->_right = cur; } //插入新的结点后,检查是否满足平衡二叉树,不满足就进行旋转 while(parent) { if (parent->_left == cur) //新增结点在左,_bf-- { parent->_bf --; } else if(parent->_right == cur) //新增结点在右,_bf++ { parent->_bf ++; } //判断父亲的平衡因子,若parent->_bf为2、-2,就进行旋转 if (parent->_bf == 0) { break; //parent的平衡因子为0,说明这棵树一定满足平衡二叉树 } else if (parent->_bf == -1 || parent->_bf == 1) { //继续更新平衡因子 cur = parent; parent = cur->_parent; } else //parent->_bf == -2 / 2 { if (parent->_bf == -2) { if(cur->_bf == -1) RotateRight(parent); else RotateLR(parent); } else { if (cur->_bf == -1) RotateRL(parent); else RotateLeft(parent); } } } return true; }旋转:
void RotateLeft(Node* parent) //左单旋 { Node* subR = parent->_right; Node* subRL = subR->_left; parent->_right = subRL; //先改变parent的右指针 if (subRL) //subRL可能为NULL { subRL->_parent = parent; } Node* ppNode = parent->_parent; subR->_left = parent; parent->_parent = subR; if (ppNode == NULL) { _root = subR; subR->_parent = NULL; } else { //判断subR应链接在ppNode的左子树还是右子树 if (ppNode->_left == parent) ppNode->_left = subR; else ppNode->_right = subR; subR->_parent = ppNode; } subR->_bf = parent->_bf = 0; } void RotateRight(Node* parent) //右单旋 { Node* subL = parent->_left; Node* subLR = subL->_right; parent->_left = subLR; if (subLR) { subLR->_parent = parent; } Node* ppNode = parent->_parent; subL->_right = parent; parent->_parent = subL; if (ppNode == NULL) //说明parent结点为根节点 { _root = subL; subL->_parent = NULL; } else { //如果parent不为根节点,判断其在上一个结点的右还是左 if (ppNode->_left == parent) ppNode->_left = subL; else ppNode->_right = subL; subL->_parent = ppNode; } subL->_bf = parent->_bf = 0; } void RotateLR(Node* parent) //左右双旋 { Node* subL = parent->_left; Node* subLR = subL->_right; int bf = subLR->_bf; RotateLeft(parent->_left); RotateRight(parent); if (bf == 0) //subLR本身就是新增节点 { parent->_bf = subL->_bf = subLR->_bf = 0; } else if(bf == 1) //subLR的右子树是新增节点 { parent->_bf = 0; subL->_bf = -1; subLR->_bf = 0; } else //bf == -1----subLR的左子树是新增结点 { parent->_bf = 1; subL->_bf = 0; subLR->_bf = 0; } } void RotateRL(Node* parent) //右左双旋 { Node* subR = parent->_right; Node* subRL = subR->_left; int bf = subRL->_bf; RotateRight(parent->_right); RotateLeft(parent); if (bf == 0) //subRL本身就是新增节点 { parent->_bf = subR->_bf = subRL->_bf = 0; } else if(bf == 1) //subRL的右子树是新增节点 { parent->_bf = -1; subR->_bf = 0; subRL->_bf = 1; } else //bf == -1----subR L的左子树是新增结点 { parent->_bf = 0; subR->_bf = 1; subRL->_bf = -1; } }三、AVL树的效率
假设一棵AVL树有N个结点,那么它的高度可以保持在lgN(log以2为底的N的对数),
插入时最好的情况就是第一次就能找到这个结点的位置进行插入,时间复杂度为O(1);最坏的情况是需要遍历整棵树的高度次,时间复杂度为O(lgN)
相关文章推荐
- 平衡搜索树-AVL树
- 浅谈平衡搜索树之AVL树
- 【平衡搜索树】AVL树
- 数据结构-平衡搜索二叉树(AVL树)
- 二叉平衡搜索树——AVL树
- 平衡搜索树之B-树
- 数据结构:关于AVL树的平衡旋转详解
- AVL树及其搜索树
- 折半搜索+状态压缩【P3067】 [USACO12OPEN]平衡的奶牛群Balanced Cow S…
- 【算法导论】 第十课 平衡搜索树
- 平衡搜索树-BTree
- AVL树的旋转平衡
- 数据结构查找(2)--平衡的二叉查找树(AVL树)
- 【数据结构】中平衡搜索树的旋转方式解析
- 数据结构:关于AVL树的平衡旋转详解
- AVL树(平衡二叉查找树)
- C++实现平衡搜索树
- 搜索:平衡2-3-4树和(左倾)红黑树
- 自平衡二叉查找树(一)-----------AVL树分析和代码实现
- 平衡搜索树之红黑树(图片格式)