AVL树被称为高度平衡的二叉搜索树,尽量降低二叉树的高度,来保持二叉树的平衡,减少树的平均搜索长度。

AVL树的性质:1、左子树和右子树的高度之差(绝对值)不超过1

2、树中的每棵子树都是AVL树,

3、每个节点都有一个平衡因子,取值为(-1,0,1),通过平衡因子来判断树的平衡。

AVL树的插入需要考虑以下的几种情况:(箭头表示要插入的方向和节点)

第一种情况:插入的节点在20的右边,但是这样导致10的平衡因子大于1所以需要进行旋转才能改变平衡因子

第二种情况:在左边插入,导致平衡因子也不满足条件,需要旋转

第三种情况:插入的节点可能不构成单旋,所以需要双旋来解决

第四种情况:与第三种情况相反的双旋

如此通过旋转就可以达到在插入的时候让此二叉树达到平衡。

实现代码如下:

//main函数#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>#include<assert.h>using namespace std;#include"AVLTree.h"int main(){testAVLTree();system("pause");return 0;}


//AVLTree  ---->  被称为高度平衡的二叉搜索树//使用三叉链来实现此二叉平衡搜索树//性质:左右高度差不超过1 && 该树的左右子树都为二叉平衡树template<class K,class V>struct AVLTreeNode{AVLTreeNode<K, V>* _left;   AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;K _key;V _value;int _bf; // 平衡因子//构造函数AVLTreeNode(const K& key,const V& value) :_left(NULL), _right(NULL), _parent(NULL), _key(key), _value(value), _bf(0){}};template<class K,class V>class AVLTree{typedef AVLTreeNode<K,V> Node;public:AVLTree() :_root(NULL){}//使用非递归的插入bool Insert(const K& key, const V& value){//如果根节点不存在说明插入的节点是第一个节点,直接new 一个即可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->_right;}else if (cur->_key>key){parent = cur;cur = cur->_left;}else{return false;}}//走到这里,说明这个节点不存在,先newcur = new Node(key, value);//比较插入节点的值与父节点的值,再考虑链上左还是右if (parent->_key < key){parent->_right = cur;cur->_parent = parent;}else if (parent->_key>key){parent->_left = cur;cur->_parent = parent;}else{while (parent){//判断cur是插在了parent的左边还是右边,再判断平衡因子是++还是--if (cur == parent->_left){parent->_bf--;}else{parent->_bf++;}//++或--之后,判断平衡因子是否等于2或等于-2if (parent->_bf == 0)    //等于0说明没有变,则跳出循环{break;}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = cur->_parent;}else if (parent->_bf == 2 || parent->_bf == -2)//如果等于2或者等于-2则不再插入,先调节为二叉平衡树再插入{//根据平衡因子来判断需要调整的树是哪种类型,再选择单旋还是双旋//如果父节点的平衡因子等于2,说明右子树比左子树高,再判断右子树的子树是在它的左边还是右边if (parent->_bf == 2){if (cur->_bf == 1){RotateL(parent);}else{RotateRL(parent);}}else{if (cur->_bf == -1)RotateR(parent);elseRotateLR(parent);}}}}return true;}//cur = parent;//右单旋void RotateR(Node* parent){//需要记录parent上面是否还有父亲节点Node* ppNode = parent->_parent;Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;//如果subLR存在  就将它的父亲置为parentif (subLR)subLR->_parent = parent;subL->_right = parent;parent->_parent = subL;//如果parent等于根节点,说明已经到第一个节点,不需要调整,直接将subL作为根即可if (parent == _root){_root = subL;subL->_parent = NULL;}else   //如果还没有到根节点还需要判断parent是左还是右{if (ppNode->_left == parent)ppNode->_left = subL;else{ppNode->_right = subL;}subL->_parent = ppNode;}}//左单旋void RotateL(Node* parent){Node* ppNode = parent->_parent;Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;//判断subRL是否存在if (subRL){subRL->_parent = parent;}subR->_left = parent;parent->_parent = subRL;if (_root == parent){_root = subR;subR->_parent = NULL;}else{if (ppNode->_left == parent)ppNode->_left = subR;elseppNode->_right = subR;subR->_parent = ppNode;}}//左右单旋void RotateLR(Node* parent){RotateL(parent->_right);RotateR(parent);}//右左单旋void RotateRL(Node* parent){RotateR(parent->_left);RotateL(parent);}void InOrder(){_InOrder(_root);cout << endl;}void _InOrder(Node* root){if (root == NULL)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}bool IsBalance(){return _IsBalance(_root);}bool _IsBalance(Node* root){if (root == NULL)return;int leftheight = _Height(root->_left);int rightheight = _Height(root->_right);return abs(rightheight - leftheight) < 2 && _IsBalance(root->_left) && _IsBalance(root->_right);}size_t _Height(Node* root){if (root == NULL)return 0;size_t left = _Height(root->_left);size_t right = _Height(root->_right);return left > right ? left + 1 : right + 1;}private:Node* _root;};void testAVLTree(){AVLTree<int, int> t;int a[] = { 16,3,7,11,9,26,18,14,15};for (int i = 0; i < (sizeof(a) / sizeof(a[0])); i++){cout<<t.Insert(a[i], 0)<<endl;}t.InOrder();}

更多相关文章

  1. go语言如何删除链表节点
  2. java对XML文件的解析、节点的增加、删除操作总结
  3. XML(4)XDocument和XmlDocument搜索指定的节点
  4. xml学习(7) .net 获取xml节点或者属性最大值
  5. FireFox对XML的处理兼容IE的节点处理方法
  6. 读写xml所有节点个人小结 和 读取xml节点的数据总结
  7. 详解XML命名空间(XML Namespaces)介绍以及节点读取方法的示例代码
  8. xml创建根节点、子节点的示例代码分享
  9. java通过XPath解析xml节点的代码详解

随机推荐

  1. Linux内核配置文档
  2. Python编程系列教程第16讲——拷贝自身到
  3. python安装第三方的包 工具对比
  4. [LeetCode] 486. Predict the Winner 预
  5. 2018年马哥人工智能&Python自动化全栈
  6. Linux--多线程之线程的取消pthread_cance
  7. 教女友学习机器学习0X02——逻辑回归
  8. linux中openssl和ssh的配置和简单应用
  9. linux python调试技巧
  10. LAMP兄弟连PHP全民总动员