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();}