【平衡搜索树】AVL树

来源:互联网 发布:hadoop linux 安装 编辑:程序博客网 时间:2024/05/22 17:40

【前言】:之前学过了二叉搜索树,但是二叉搜索树有一个很大的缺陷,就是当当原本的数据有序或者接近有序的时候,这棵树的高度就为N(假设原本的数据个数为N),那么在搜索的时候它的时间复杂度(这里考虑最坏情况下的)就为O(N), 搜索的效率就比较低。那么,为了改进这个缺陷,我们就尽量让这棵搜索树变得比较平衡,降低它的高度,这样就可以提高它的搜索效率。

AVL树

一、定义:
AVL树又称为
高度平衡的二叉搜索树,它能保持搜索二叉树的高度平衡,尽量降低树的高度,减少树的平均搜索长度,从而提高搜索的效率。

二、性质:

1. 左右子树高度差的绝对值 <= 1
2. AVL树的每个左子树和右子树仍是AVL树
3. 每个节点都有一个平衡因子(balancefactor--bf) = 右子树高度 - 左子树高度,任一结点的平衡因子是-1,0,1。

三、结点结构设计:

因为每个节点都需要判断以这个结点为根的这棵树是否平衡,所以我们要在搜索二叉树结点的基础上加上判断这棵树是否平衡的变量。

有两种思路:(1)加入当前树的高度  (2)加入平衡因子,我们选择第二种思路。

结点的结构定义如下:

<span style="font-size:18px;">template <class K, class V>struct AVLTreeNode{K _key; //关键码V _value;AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;int _bf; //平衡因子};</span>

四、实现思路:

对于搜索树,我们主要实现它的三个接口:插入(Insert),删除(Remove)和 查找(Find)。

查找和我们搜索二叉树的基本一样,主要是插入和删除,这两个思想一致,我们这里就分析一下实现插入的思路。


插入主要步骤:

1.首先,和搜索二叉树一样,先把新结点插入进去;

2.调整平衡因子:向左插入平衡因子-1,向右插入+1;

3.检查平衡因子,调整这棵树:(如下图解释)

    (1)当平衡因子为 1/-1, 继续向父节点调整,直到父节点为空;

    (2)当平衡因子为 0, 则不需要向父节点调整,跳出循环;

    (3)当平衡因子为 2/-2,则需要旋转,使该节点平衡因子变为0,然后跳出循环。

                  

 

五、搜索的时间复杂度:O(logN)

六、下面附上实现代码和测试用例

1.AVLTree.h

#pragma once#include<iostream>using namespace std;template <class K, class V>struct AVLTreeNode{K _key;V _value;AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;int _bf; //平衡因子AVLTreeNode(const K& key, const V& value):_key(key),_value(value),_left(NULL),_right(NULL),_parent(NULL),_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){if(_root == NULL){_root = new Node(key, value);return true;}//查找插入位置Node* parent = NULL; Node* cur = _root;while(cur){if(cur->_key > key){parent = cur;cur = cur->_left;}else if(cur->_key < key){parent = cur;cur = cur->_right;}elsereturn false;}//插入cur = new Node(key, value);if(parent->_key > key) //parent的左插入{parent->_left = cur;cur->_parent = parent;//调整平衡因子--parent->_bf;_AdjustTree(parent);}else//parent的右插入{parent->_right = cur;cur->_parent = parent;++parent->_bf;_AdjustTree(parent);}return true;}void InOrder(){_InOrder(_root);cout << endl;}bool IsBalance(){return _IsBalance(_root);}~AVLTree(){_Release(_root);}protected:void _Release(Node* root){if(root == NULL)return;_Release(root->_left);_Release(root->_right);delete root;root = NULL;}void _AdjustTree(Node* parent){//检查平衡因子while(parent){if(parent->_bf == 0)//平衡因子为0,停止break;else if(parent->_bf == 1 ||parent->_bf == -1)//平衡因子为1/-1,继续向父结点调整{Node* sub = parent;parent = parent->_parent;if(parent){if(parent->_left == sub)--parent->_bf;else++parent->_bf;}}else//平衡因子为2/-2,旋转{if(parent->_bf==2 && parent->_right->_bf==1){//左旋_RotateL(parent);}else if(parent->_bf==2 && parent->_right->_bf==-1){//右左双旋_RotateRL(parent);}else if(parent->_bf==-2 && parent->_left->_bf==-1){//右旋_RotateR(parent);}else //parent->_ba==-2 && parent->_left->_ba==1{//左右双旋_RotateLR(parent);}break;}}}//右旋void _RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;//subLR 和 parentparent->_left = subLR;if(subLR) //注意:有可能为空subLR->_parent = parent;//subL 和 ppNode* pp = parent->_parent;subL->_parent = pp;if(pp){if(pp->_left == parent)pp->_left = subL;elsepp->_right = subL;}else{_root = subL;subL->_parent = NULL;}//subL 和 parentsubL->_right = parent;parent->_parent = subL;//改平衡因子subL->_bf = parent->_bf = 0;}void _RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;//subRL 和 parentparent->_right = subRL;if(subRL) //注意:有可能为空subRL->_parent = parent;//pp 和 subRNode* pp = parent->_parent;subR->_parent = pp;if(pp){if(pp->_left == parent)pp->_left = subR;elsepp->_right = subR;}else{_root = subR;subR->_parent = NULL;}//parent 和 subRsubR->_left = parent;parent->_parent = subR;//改平衡因子subR->_bf = parent->_bf = 0;}void _RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;_RotateR(parent->_right);_RotateL(parent);if(bf == 0){parent->_bf = subR->_bf = subRL->_bf;}else if(bf == 1){parent->_bf = -1;subRL->_bf = 0;subR->_bf = 0;}else{parent->_bf = 0;subRL->_bf = 0;subR->_bf = 1;}}void _RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR->_bf;_RotateL(parent->_left);_RotateR(parent);if(bf == 0){subLR->_bf = subL->_bf = parent->_bf = 0;}else if(bf == 1){parent->_bf = 0;subLR->_bf = 0;subL->_bf = -1;}else{parent->_bf = 1;subLR->_bf = 0;subL->_bf = 0;}}void _InOrder(Node* root){if(root == NULL)return;_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}size_t _Height(Node* root){if(root == NULL)return 0;size_t LHeight = _Height(root->_left);size_t RHeight = _Height(root->_right);return (LHeight>RHeight) ? (LHeight+1) : (RHeight+1);}bool _IsBalance(Node* root){if(root == NULL)return true;int bf = _Height(root->_right)-_Height(root->_left);if(bf != root->_bf)cout << "平衡因子异常 key:"<<root->_key<< endl;if(abs(bf) < 2)return _IsBalance(root->_left) && _IsBalance(root->_right);elsereturn false;}protected:Node* _root;};


2.Test.cpp

#include<iostream>#include"AVLTree.h"using namespace std;//测试用例一void TestAVLTree1(){int arr[] = {16, 3, 7, 11, 9, 26, 18, 14, 15};AVLTree<int, int> t1;for(int i = 0; i<sizeof(arr)/sizeof(arr[0]); ++i){t1.Insert(arr[i], i);}t1.InOrder();cout<<"IsBalance() ? "<<t1.IsBalance()<<endl;}//测试用例二void TestAVLTree2(){int arr[] = {4, 2, 6, 1, 3, 5, 15, 7, 16, 14};AVLTree<int, int> t2;for(int i = 0; i<sizeof(arr)/sizeof(arr[0]); ++i){t2.Insert(arr[i], i);}t2.InOrder();cout<<"IsBalance() ? "<<t2.IsBalance()<<endl;}int main(){TestAVLTree1();cout << endl;TestAVLTree2();return 0;}



0 0
原创粉丝点击