AVL树插入删除
C++实现AVL树的完整代码

C++实现AVL树的完整代码AVL树的介绍AVL树是⼀种⾃平衡的⼆叉搜索树,它通过单旋转(single rotate)和双旋转(double rotate)的⽅式实现了根节点的左⼦树与右⼦树的⾼度差不超过1,。
这有效的降低了⼆叉搜索树的时间复杂度,为O(log n)。
那么,下⾯⼩编将详细介绍C++实现AVL 树的代码。
最后⼀步提供可靠的代码实现这⾥先粘贴代码给⼤家的忠告,⼀定要及时去实现,不然之后再实现要花更多的时间/**平衡⼆叉树应该有些功能*插⼊删除查找*前序遍历中序遍历后序遍历层次遍历*统计结点数⽬*///代码已经调好,写了很久才写出来#ifndef _AVLTREE_#define _AVLTREE_#include<iostream>#include<vector>#include<queue>#include<map>using namespace std;#define MAXFACTOR = 2;template<class Key , class E>class AVLNode{private:Key key;E value;AVLNode<Key,E>* left;AVLNode<Key,E>* right;AVLNode<Key,E>* parent;public:AVLNode():left(nullptr),right(nullptr),parent(nullptr){}AVLNode(Key _key,E _value , AVLNode<Key,E>* _parent = nullptr,AVLNode<Key,E>*_left = nullptr, AVLNode<Key,E>*_right = nullptr):key(_key),value(_value),left(_left),right(_right),parent(_parent){}bool isLeaf(){return left==nullptr && right == nullptr ;}//元素设置Key getKey() const { return key;}void setKey(Key set) {key = set;}E getValue() const { return value;}void setValue(E set) {value = set;}AVLNode<Key,E>* getLeft() { return left; }void setLeft (AVLNode< Key,E >* set){ left = set;}AVLNode<Key,E>* getRight() { return right;}void setRight (AVLNode<Key,E>* set) {right = set ;}AVLNode<Key,E>* getParent() {return parent;}void setParent(AVLNode<Key,E>* set) { parent = set;}};template<class Key , class E>class AVLTree{private:AVLNode<Key,E>* root;void clear(AVLNode<Key,E>* &r){if(r==nullptr)return;delete r;}void Init(){root = new AVLNode<Key,E>();root=nullptr;}void preOrder(AVLNode<Key,E>* r,void(*visit) (AVLNode<Key,E> * node)) {if(r==nullptr)return;(*visit) (r);preOrder(r->getLeft() , visit);preOrder(r->getRight(), visit);}void inOrder(AVLNode<Key,E>* r , void(*visit)(AVLNode<Key,E>* node) ) {if(r==nullptr)return;inOrder(r->getLeft() , visit);(*visit)(r);inOrder(r->getRight(),visit);}void postOrder(AVLNode<Key,E>*r , void (*visit) (AVLNode<Key,E>* node)) {if(r==nullptr)return;postOrder(r->getLeft(),visit);postOrder(r->getRight(),visit);(*visit)(r);}void levelOrder(AVLNode<Key,E>*r , void (*visit) (AVLNode<Key,E>* node)) {queue< AVLNode<Key,E>* > q;if(r==nullptr)return;q.push(r);while( ! q.empty() ){AVLNode<Key,E>* tmp = q.front();q.pop();(*visit)(tmp);if(tmp->getLeft() ) q.push(tmp->getLeft() );if(tmp->getRight()) q.push(tmp->getRight());}}AVLNode<Key,E>* find(AVLNode<Key,E>* r,Key k){if(r==nullptr)return nullptr;if(k == r->getKey() ) return r;else if( k < r->getKey()){find(r->getLeft(),k);}else {find(r->getRight(),k);}}//Find the smallest element in the avl treeAVLNode<Key,E>* getMin(AVLNode<Key,E>* r){if(r->getLeft() == nullptr) return r;else{getMin(r->getLeft());}}//Remove the smallest elementAVLNode<Key,E>* deleteMin(AVLNode<Key,E>* rt){if(rt->getLeft() == nullptr) return rt->getRight();else{rt->setLeft(deleteMin(rt->getLeft()));}AVLNode<Key,E>* leftRotate(AVLNode<Key,E>* node){if( node == nullptr) return nullptr;AVLNode<Key,E>* newHead = node->getRight();node->setRight( newHead -> getLeft() );newHead -> setLeft( node );return newHead;}AVLNode<Key,E>* rightRotate(AVLNode<Key,E>* node){if(node == nullptr)return nullptr;AVLNode<Key,E>* newHead = node->getLeft();node->setLeft( newHead->getRight() );newHead ->setRight(node);return newHead;}int getHeight(AVLNode<Key,E>*node){if(node == nullptr)return 0;if(node->isLeaf())return 1;else return ( getHeight( node->getLeft() ) > getHeight( node->getRight() ) ? getHeight( node->getLeft() ) : getHeight( node->getRight() ) ) + 1; }int getBalanceFactor(AVLNode<Key,E>* node){return getHeight(node->getLeft()) - getHeight(node->getRight() );}AVLNode<Key,E>* balance(AVLNode<Key,E>* node){if(!node) return nullptr;else if ( getBalanceFactor( node ) == 2){if(getBalanceFactor( node ->getLeft() ) == 1){node = rightRotate(node);}else{node->setLeft(leftRotate( node->getLeft() ) );node = rightRotate(node);}}else if(getBalanceFactor( node ) == -2){if(getBalanceFactor( node->getRight()) == -1){node = leftRotate(node);}else{node->setRight( rightRotate( node->getRight() ) );node = leftRotate(node);}}return node;}AVLNode<Key,E>* insert( AVLNode<Key,E>* root ,const pair<Key,E>& it) {if(root == nullptr){return new AVLNode<Key,E>(it.first , it.second,NULL,NULL,NULL);}else if (it.first < root->getKey() ){root ->setLeft( insert(root->getLeft() , it) ) ;}else{root ->setRight( insert(root->getRight() , it) );root = balance(root);return root;}AVLNode<Key,E>* remove(AVLNode<Key,E>* node , const Key k){if(node == nullptr) return nullptr;if(node->getKey() > k){node->setLeft( remove(node->getLeft() , k) );node = balance(node);}else if(node->getKey() < k){node->setRight( remove(node->getRight(), k) );node = balance(node);}else if(node->getKey() == k){if(! node->isLeaf() ){AVLNode<Key,E>* tmp = getMin(node->getRight() );node->setKey( tmp->getKey() );node->setValue( tmp->getValue() );node->setRight( deleteMin(node->getRight() ) );delete tmp;}else {AVLNode<Key,E>* tmp = node;node = (node->getLeft() != nullptr) ? node->getLeft() : node->getRight() ; delete tmp;}}return node;}public:~AVLTree(){clear(root);}AVLTree(){/*Init();*/ root = nullptr; }//四种遍历⽅式void preOrder( void (*visit)(AVLNode<Key,E>* r)){preOrder(root,visit);}void inOrder(void (*visit)(AVLNode<Key,E>* r)){inOrder(root,visit);}void postOrder(void (*visit)(AVLNode<Key,E>* r)){postOrder(root,visit);}void levelOrder( void(*visit)(AVLNode<Key,E>*r) ){levelOrder(root,visit);}//插⼊void insert(const pair<Key,E> &it){root = insert(root,it);}//删除void remove(const Key& k){remove(root,k);}bool find(const Key&k){return find(root,k);}};#endif//AVLtest.cpp#include"NewAvl.h"#include<iostream>using namespace std;template<typename Key,typename E>void traverse(AVLNode<Key,E>* root){cout<<root->getKey()<<" "<<root->getValue()<<" "; cout<<endl;}int main(){AVLTree<int,int>* tree = new AVLTree<int ,int>; for(int i = 0 ; i < 5 ; i ++){tree->insert(make_pair(i,i));}tree->remove(1);cout<<"PreOrder: "<<endl;tree->preOrder(traverse);cout<<endl;cout<<"LevelOrder: "<<endl;tree->levelOrder(traverse);cout<<endl;cout<<"InOrder: "<<endl;tree->inOrder(traverse);cout<<endl;cout<<"PostOrder: "<<endl;tree->postOrder(traverse);cout<<endl;cout<<tree->find(2)<<endl;tree->insert(make_pair(9,9));tree->levelOrder(traverse);}运⾏结果以上就是C++实现AVL树的完整代码的详细内容,更多关于C++ AVL树的资料请关注其它相关⽂章!。
avl使用规则

AVL树是一种自平衡二叉搜索树,其使用规则如下:
当插入一个新节点时,需要进行旋转操作以保持树的平衡。
旋转操作包括单旋转和双旋转,具体使用哪种旋转取决于插入节点后树的平衡情况。
在删除一个节点时,也需要进行旋转操作来重新平衡树。
同样地,旋转操作包括单旋转和双旋转,具体使用哪种旋转取决于删除节点后树的平衡情况。
除了插入和删除操作外,其他基本操作如搜索、查找等与普通的二叉搜索树类似。
需要注意的是,AVL树虽然能保证查询效率较高,但在插入和删除节点时需要进行旋转操作,这些操作可能会使得时间复杂度不再是O(log n),因此在数据量很大且插入删除频率较高的情况下,可能会比普通的二叉搜索树性能较差。
以上是关于AVL树使用规则的简要介绍,如有需要,可以阅读数据结构相关书籍或请教专业人士。
树结构的定义和基本操作

树结构的定义和基本操作树结构是一种非线性的数据结构,其形状类似于自然界中的树。
树由一组节点(或称为顶点)和一组连接这些节点的边组成。
树结构的常见学习对象有二叉树、二叉树、AVL树、红黑树等。
树结构的基本操作包括创建、插入、删除、查找和遍历。
首先,创建树结构需要定义树节点的结构。
每个节点至少包含一个数据元素以及指向其子节点的指针。
树结构可以使用链式存储结构或数组存储结构。
1.创建树结构:树结构的创建有多种方式。
其中一种常见的方法是通过递归实现。
递归函数首先创建根节点,然后再递归地创建根节点的左子树和右子树。
2.插入节点:要插入一个新节点,首先要定位到合适的位置。
比较要插入的节点值与当前节点值的大小,如果小于当前节点,则进入左子树,如果大于当前节点,则进入右子树。
最终找到合适的位置插入新节点。
如果要插入的节点已经存在,可以替换或忽略该节点。
3.删除节点:删除节点分为三种情况:删除叶子节点、删除只有一个子节点的节点、删除有两个子节点的节点。
-删除叶子节点:直接删除即可。
-删除只有一个子节点的节点:将子节点与父节点连接起来,删除当前节点。
-删除有两个子节点的节点:找到当前节点的后继节点(比当前节点大的最小节点),将后继节点的值复制到当前节点,然后删除后继节点。
4.查找节点:树的查找可以使用递归或迭代的方式实现。
递归方式从根节点开始,根据节点值与目标值的大小关系递归地遍历左子树或右子树,直到找到目标值或遍历完成。
迭代方式使用循环和栈或队列的数据结构来实现。
5.遍历节点:树的遍历有三种方式:前序遍历、中序遍历和后序遍历。
-前序遍历:根节点->左子树->右子树-中序遍历:左子树->根节点->右子树-后序遍历:左子树->右子树->根节点树的遍历也可以通过递归或迭代的方式实现。
递归方式较为简单,使用迭代方式需要借助栈或队列来保存遍历的节点。
除了上述基本操作外,树结构还有一些扩展的操作,如树的深度计算、查找最大值或最小值、查找前驱节点或后继节点等。
AVL树的c语言实现

AVL树的c语言实现AVL树的c语言实现导语:C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的'机器码以及不需要任何运行环境支持便能运行的编程语言。
下面我们来看看AVL树的c语言实现,希望对大家有所帮助。
AVL树的c语言实现:在计算机科学中,AVL树是最先发明的自平衡二叉查找树。
在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。
查找、插入和删除在平均和最坏情况下都是O(log n)。
增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。
1.节点(1)节点的定义1 2 3 4 5 6 7 8 9 typedef int KeyType;typedef struct AvlNode{KeyType key; //数据AvlNode *leftchild; //左孩子AvlNode *rightchild; //右孩子AvlNode *parent; //双亲结点int balance; //平衡因子}AvlNode,*AvlTree;(2)结点的创建1 2 3 4 5 6 7 8 9101112 AvlNode *BuyNode(){AvlNode *p =(AvlNode *)malloc(sizeof(AvlNode));if( p != NULL){p->leftchild = NULL;p->rightchild = NULL;p->parent = NULL;p->balance = 0;}return p;}2.旋转如果在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡。
这种失去平衡的可以概括为4种姿态:左单旋转,右单旋转,左平衡,右平衡。
(1)左单旋转:也叫左左旋转。
【AVL树的c语言实现】。
算法工程师面试真题单选题100道及答案解析

算法工程师面试真题单选题100道及答案解析1. 以下哪种数据结构适合用于实现快速查找最大值和最小值?A. 栈B. 队列C. 堆D. 链表答案:C解析:堆可以快速地获取最大值和最小值。
2. 快速排序在最坏情况下的时间复杂度是?A. O(nlogn)B. O(n^2)C. O(n)D. O(logn)答案:B解析:快速排序在最坏情况下,每次划分都极不均匀,时间复杂度为O(n^2)。
3. 以下哪种算法常用于在未排序的数组中查找特定元素?A. 冒泡排序B. 二分查找C. 顺序查找D. 插入排序答案:C解析:顺序查找适用于未排序的数组查找特定元素。
4. 一个有向图的邻接表存储结构中,顶点的邻接点是按照什么顺序存储的?A. 随机顺序B. 顶点编号的大小顺序C. 插入的先后顺序D. 无法确定答案:C解析:邻接表中顶点的邻接点是按照插入的先后顺序存储的。
5. 深度优先搜索遍历图的时间复杂度是?A. O(n)B. O(n + e)C. O(n^2)D. O(e)答案:B解析:深度优先搜索遍历图的时间复杂度为O(n + e),其中n 是顶点数,e 是边数。
6. 以下哪种排序算法是稳定的排序算法?A. 快速排序B. 希尔排序C. 冒泡排序D. 选择排序答案:C解析:冒泡排序是稳定的排序算法。
7. 一个具有n 个顶点的无向完全图,其边的数量为?A. n(n - 1) / 2B. n(n - 1)C. n^2D. 2n答案:A解析:无向完全图的边数为n(n - 1) / 2 。
8. 动态规划算法的基本思想是?A. 分治法B. 贪心算法C. 把问题分解成多个子问题并保存子问题的解D. 回溯法答案:C解析:动态规划的基本思想是把问题分解成多个子问题并保存子问题的解,避免重复计算。
9. 以下关于哈希表的说法,错误的是?A. 哈希表的查找时间复杂度为O(1)B. 哈希冲突可以通过开放定址法解决C. 哈希表的空间复杂度是固定的D. 哈希函数的设计会影响哈希表的性能答案:C解析:哈希表的空间复杂度不是固定的,取决于元素数量和负载因子等。
AVL树和红黑树的性能对比和适用场景

AVL树和红黑树的性能对比和适用场景AVL树和红黑树都是常用的自平衡二叉查找树,它们在不同的应用场景下具有不同的性能特点。
本文将对AVL树和红黑树的性能进行对比,并分析它们适用的场景。
一、性能对比1. 插入和删除操作AVL树和红黑树在插入和删除操作方面具有不同的性能表现。
由于AVL树要求保持平衡,每次插入或删除操作后都需要进行旋转操作来调整树的平衡。
这样虽然能够保持树的平衡,但是会造成频繁的旋转操作,导致性能较低。
而红黑树则通过颜色标记和旋转操作来保持树的平衡,相比AVL树的旋转操作更少,因此在插入和删除操作方面性能更优。
2. 查找操作在查找操作方面,AVL树和红黑树的性能相当。
它们都保持了二叉查找树的性质,可以在对数时间内完成查找操作。
3. 内存占用由于AVL树要存储额外的平衡信息,每个节点需要额外的一个整数来表示平衡因子,因此相比红黑树来说,AVL树的内存占用更高。
二、适用场景1. 数据插入与删除频繁的场景如果应用场景中涉及频繁的数据插入和删除操作,而对查找操作的性能要求相对较低,则适合选择红黑树。
红黑树通过更少的旋转操作来保持树的平衡,能够在频繁插入和删除操作时,保持较好的性能。
2. 数据查询频繁的场景如果应用场景中涉及频繁的数据查询操作,而对插入和删除操作的性能要求相对较低,则适合选择AVL树。
AVL树由于保持了严格的平衡性,能够在频繁查询操作时,提供更高的查找性能。
3. 对内存占用有限制的场景如果应用场景对内存占用有较严格的限制,则适合选择红黑树。
红黑树相比AVL树的内存占用更低,能够在有限的内存条件下,存储更多的节点。
4. 平衡性要求高且内存占用不是关键问题的场景如果应用场景对平衡性要求较高,而对内存占用没有过多的限制,则AVL树是更好的选择。
AVL树能够保持严格的平衡性,但相对红黑树来说,需要更多的旋转操作,导致性能较低。
三、总结AVL树和红黑树是常用的自平衡二叉查找树,在不同的应用场景下具有不同的性能表现。
太空人平衡树的技巧-概述说明以及解释

太空人平衡树的技巧-概述说明以及解释1.引言1.1 概述太空人平衡树是一种旨在解决二叉搜索树不平衡的问题的数据结构。
它通过使用节点的"权重"来调整树的结构,使得左子树和右子树的高度差尽量小,从而提供更快速的搜索和插入操作。
太空人平衡树的技巧是一套操作和策略,用于在实际应用中有效地构建和维护平衡的树结构。
这些技巧包括节点的旋转、子树的重建以及权重调整等操作。
通过旋转操作,太空人平衡树可以根据特定情况将节点进行左旋或右旋,从而重新构建树的结构。
这样,较高的子树可以通过旋转操作被转移到较低的位置,使得左子树和右子树的高度差得以减小。
另外,当进行插入或删除操作时,太空人平衡树会通过重建子树的方式来调整整个树的平衡。
这意味着,在插入或删除节点时,可能需要将一部分子树重新构建,以保持整个树的平衡状态。
权重调整是太空人平衡树中的一个重要操作,在插入或删除节点后,树的权重可能会发生变化。
通过适时地增加或减少节点的权重,太空人平衡树可以保持树的整体平衡,避免发生不平衡的情况。
总而言之,太空人平衡树的技巧是一种有效解决二叉搜索树不平衡问题的方法。
通过合理地运用节点旋转、子树重建以及权重调整等操作和策略,可以构建出一个高效、平衡的数据结构,提供更快速的搜索和插入操作。
在接下来的文章中,我们将详细介绍太空人平衡树的基本原理以及实际操作技巧。
1.2文章结构本文包括引言、正文和结论等3个子章节。
引言部分概述了太空人平衡树的技巧,并介绍了本文的目的。
正文部分分为两个部分,即基本原理和技巧讲解。
基本原理部分解释了太空人平衡树的基本原理,包括其数据结构和算法等方面的内容。
技巧讲解部分则介绍了太空人平衡树的实际操作技巧,包括如何构建太空人平衡树和应用中的注意事项等。
结论部分总结了太空人平衡树的技巧和应用,以及展望了其未来的发展方向。
通过本文的阅读,读者可以全面了解太空人平衡树的相关知识和在实际应用中的技巧。
1.3 目的本文的目的是探讨太空人平衡树的技巧及其应用。
AVL树及其平衡性

AVL树及其平衡性AVL树是一种自平衡的二叉搜索树,它得名于它的发明者Adelson-Velsky和Landis。
AVL树在插入和删除节点时会通过旋转操作来保持树的平衡,以确保树的高度始终保持在一个较小的范围内,从而提高搜索、插入和删除操作的效率。
本文将介绍AVL树的基本概念、特点以及如何保持其平衡性。
一、AVL树的基本概念AVL树是一种二叉搜索树,具有以下特点:1. 每个节点最多有两个子节点,左子节点的值小于父节点的值,右子节点的值大于父节点的值;2. 每个节点都有一个平衡因子(Balance Factor),定义为左子树的高度减去右子树的高度;3. AVL树的平衡因子必须为-1、0或1,即任意节点的左右子树高度差不超过1;4. AVL树中任意节点的左子树和右子树都是AVL树。
二、AVL树的平衡性AVL树通过旋转操作来保持树的平衡,主要包括左旋转、右旋转、左右旋转和右左旋转四种操作。
在插入或删除节点后,如果AVL树的平衡因子不满足要求,就需要进行相应的旋转操作来调整树的结构,以保持平衡性。
1. 左旋转(LL旋转)当某个节点的平衡因子为2,且其左子树的平衡因子为1或0时,需要进行左旋转操作。
左旋转是将当前节点向左旋转,使其右子节点成为新的根节点,原根节点成为新根节点的左子节点,新根节点的左子节点成为原根节点的右子节点。
2. 右旋转(RR旋转)当某个节点的平衡因子为-2,且其右子树的平衡因子为-1或0时,需要进行右旋转操作。
右旋转是将当前节点向右旋转,使其左子节点成为新的根节点,原根节点成为新根节点的右子节点,新根节点的右子节点成为原根节点的左子节点。
3. 左右旋转(LR旋转)当某个节点的平衡因子为2,且其左子树的平衡因子为-1时,需要进行左右旋转操作。
左右旋转是先对当前节点的左子节点进行右旋转,然后再对当前节点进行左旋转。
4. 右左旋转(RL旋转)当某个节点的平衡因子为-2,且其右子树的平衡因子为1时,需要进行右左旋转操作。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
AVL树插入删除
AVL树是一种平衡二叉树,其每个节点的左右子树高度最多差1,空树高度定为-1,当左右的高度超过1,即失去了平衡,不是AVL树了。
private static class AVLNode<AnyType>{
AVLNode (AnyType element)
{this(element ,null,null);}
AVLNode(AnyTape element,AVLNode<AnyType> left,AVLNode<AnyType> right){
this.element = element;
this.left = left;
this.right = right;
}
AnyTape element;
AVLNode<AnyType> left;
AVLNode<AnyType> right;
int height;
}
这是AVL树的节点声明,声明了节点,左右子树以及高度。
在进行插入和删除操作时可能会使AVL树左右子树的高度相差超过1,破坏了平衡,当平衡破坏时,在插入或删除完成前恢复平衡要进行旋转。
旋转分为单旋转和双旋转。
把必须重新平衡的节点叫做t,下面是单旋转和双旋转的情况。
1.对于t的左儿子的左子树进行插入->单旋转
2.对于t的左儿子的右子树进行插入->双旋转
3.对于t的右儿子的左子树进行插入->双旋转
4.对于t的右儿子的右子树进行插入->单旋转
由此总结,左-左,右-右是单旋转,左-右,右-左是双旋转
在旋转之前,插一下节点高度计算
private int height(AVLNode<AnyType> t){
return t == null ? -1 : t.height;
}
1.左-左:单旋
private AVLNode<AnyType> rotateLeftChild(AVLNode<AnyType> k1){ AVLNode<AnyType> k2 = k1.right;
k1.right = k2.left;
k1.height = Maht.max(height(k1.left),height(k1.right))+1; k1.height = Maht.max(height(k2.right),k1.height)+1;
return k2;
}
2.左-右:双旋转
private AVLNode<AnyType> doubleLeftChild(AVLNode<AnyType> k3){ k3.left = rotateReft(k3.left);
return rotateLeft(k3);
}
3.右-左:双旋转
private AVLNode<AnyType> doubleRightChild(AVLNode<AnyType> k3){
k3.right = rotateLeftChild(k3.right);
return rotateRightChild(k3);
}
4.右-右:单旋
private AVLNode<AnyType> rotateRightChild(AVLNode<AnyType> k2){
AVLNode<AnyType> k1 = k2.left;
k2.left = k1.right;
k2.height = Maht.max(height(k2.left),height(k2.right))+1;
k1.height = Maht.max(height(k1.left),k2.height)+1;
return k1;
}
说完了旋转,接下来就是插入操作了
private AVLNode<AnyType> insert(AnyType x,AVLNode<AnyType>t){
if(t == null)
return new AVLNode<>(x,null,null);
int result = pareTo(t.element);
if( result < 0) //如果X小于节点值,则在左子树插入,递归更新
t.left = insert(x,t.left);
else if( result > 0) //如果X大于节点值,则在右子树插入,递归 t.right = insert(x,t.right);
return balance(t);
}
private static final int balance_num = 1;
private AVLNode<AnyType> balance(AVLNode<AnyType>t){
if(t == null)
return t;
if(height(t.left) - height(right) > balance_num){
if(height(t.left.left) > height(t.left.right)) //左-左
t = rotateLeftChild(t);
else
t = doubleLeftChild(t); //左-右
}else{
if(height(t.right.right) > height(t.right.left)) //右-左 t = rotateRightChild(t);
else
t = doubleRightChild(t); //右-左
}
t.height = Math.max(height(t.left),height(t.right))+1;
return t;
}
旋转一定要保持平衡,所以要返回的是balance(t)而不是t。
接下来进行删除操作,删除较插入更为复杂。
private AVLNode<AnyType> remove(AnyType x,AVLNode<AnyType>t){
if(t == null)
return new AVLNode<>(x,null,null);
int result = pareTo(t.element);
if( result < 0) //如果X小于节点值,则在左子树删除,递归更新
t.left = insert(x,t.left);
else if( result > 0) //如果X大于节点值,则在右子树删除,递归 t.right = insert(x,t.right);
else if(t.left != null && t.right != null){
t.element = findMin(t.right).element; //找到右子树最小值 t.right = remove(t.element,t.right) //删除右子树最小值原来的位置
}
else
t = (t.left != null)?t.left:t.right; //如果是一个儿子或者没有,哪个儿子不为空就返回哪个儿子
return balance(t);
}
总体来说删除操作和二叉搜索树的想法包括代码都几乎是一致的,但是重要不同的一点就是AVL树需要进行旋转重平衡。
理解了旋转就基本上插入删除思路想法和二叉搜索都一致。