个人理解
AVL tree (named after inventors Adelson-Velsky and Landis) is a self-balancing binary search tree (https://en.wikipedia.org/wiki/AVL_tree)
自平衡二叉搜索树AVL,在二叉搜索树的基础上加了个限制条件,所有左子树与右子树的高度差不超过1,其他和二叉搜索数一样。
平衡二叉树细节
节点定义
节点中除了包含数据,左节点,右节点外,还包含了当前节点作为根时的高度。新建一个节点时一定要将左节点和右节点置为NULL,否则可能出现指向不确定位置出现错误。
typedef int T;
struct TreeNode{
T val; //关键字
int height;//当前节点的高度
TreeNode * left;
TreeNode * right;
TreeNode(T v):val(v),left(NULL),right(NULL),height(0){}
};
树的定义
将AVL定义为class
class AVL{
private:
TreeNode * root;
TreeNode * LL(TreeNode * node);//左左旋
TreeNode * RR(TreeNode * node);//右右旋
TreeNode * LR(TreeNode * node);//左右旋
TreeNode * RL(TreeNode * node);//右左旋
int tree_height(TreeNode * node);//树的高度
TreeNode * insert(TreeNode * node,T val);//插入节点
TreeNode * remove(TreeNode * root,TreeNode * node);//删除节点
TreeNode * search(TreeNode * root,T val);//搜索
void _pre_order(TreeNode*node);//先序遍历
void _in_order(TreeNode*node);//中序遍历
void _post_order(TreeNode*node);//后序遍历
TreeNode* _min_node(TreeNode*);//最小节点
TreeNode* _max_node(TreeNode*);//最大节点
void _del(TreeNode * root);//删除全部树的结构,清除空间
public:
AVL(){root = NULL;}
~AVL(){_del(root);}
void destroy(){_del(root);root=NULL;}
int tree_height();
int insert(T val);
int remove(T val);
void pre_order();
void in_order();
void post_order();
TreeNode * search(T val);
};
添加节点
在二叉搜索树的基础上添加后,判断是否满足平衡,不满足就调整。调整的过程主要是4种旋转。
LL-左左旋
当前根节点的左子树 的 左子树 还有子树,而根节点的右子树无子树,需要进行左左旋LL。
把k1的右节点y变为k2左子树,根节点k2变为左子树k1的右子树,k1变为根节点。更新树的高度。
TreeNode* AVL::LL(TreeNode * node){
// k2 k1
// / \ / \
// k1 z x k2
// / \ => / / \
// x y T y z
// /
// T
TreeNode * k2 = node;
TreeNode * k1 = k2->left;
k2->left = k1->right;
k1->right = k2;
k2->height = MAX( tree_height(k2->left),tree_height(k2->right)) + 1;
k1->height = MAX( tree_height(k1->left),k2->height) + 1;
return k1;
}
RR-右右旋
当前根节点的右子树 的 右子树 还有子树,而根节点的左子树无子树,需要进行右右旋RR。
把k2的左节点y变为k1右子树,根节点k1变为右子树k2的左子树,k2变为根节点。更新树的高度。
TreeNode* AVL::RR(TreeNode * node){
// k1 k2
// / \ / \
// x k2 k1 z
// / \ => / \ \
// y z x y T
// \
// T
TreeNode * k1 = node;
TreeNode * k2 = k1->right;
k1->right = k2->left;
k2->left = k1;
k1->height = MAX( tree_height(k1->left),tree_height(k1->right)) + 1;
k2->height = MAX( tree_height(k2->right),k1->height) + 1;
return k2;
}
LR-左右旋
当前根节点的左子树 的 右子树还有子树,而根节点的右子树无子树。此时需要左右旋LR。
对左子树执行RR(root->left)
再对当前树执行LL(root)
TreeNode* AVL::LR(TreeNode * node){
// 左孩子的右孩子有节点
node->left = RR(node->left);
return LL(node);
}
RL-右左旋
目录
对右子树执行LL(root->right)
再对当前树执行LL(root)
TreeNode* AVL::RL(TreeNode * node){
// 右孩子的左孩子有节点
node->right = LL(node->right);
return RR(node);
}
添加节点代码
TreeNode* AVL::insert(TreeNode * node,T val){
// 插入数据
if(node == NULL){
node = new TreeNode(val);
}else if(val < node->val){
//插入到左子树
node->left = insert(node->left,val);
//若失去平衡,调整
if(tree_height(node->left) - tree_height(node->right)==2){
if(val<node->left->val){
// 插入到左子树的左子树上导致失衡,执行LL
node = LL(node);
}else{
node = LR(node);
}
}
}else if(val>node->val){
//插入到右子树
node->right = insert(node->right,val);
if(tree_height(node->right) - tree_height(node->left)==2){
if(val>node->right->val){
node = RR(node);
}else{
node = RL(node);
}
}
}else{
// 添加相同的节点
// return NULL;
cout<<"添加相同的节点";
}
node->height = MAX( tree_height(node->left),tree_height(node->right) ) + 1;
return node;
}
int AVL::insert(T val){
TreeNode*p = insert(root,val);
if(p){
this->root = p;
return 0;
}else{
return -1;
}
}
删除节点
删除节点后,如果不平衡就进行调整,也是上面的4中旋转
代码
TreeNode* AVL::remove(TreeNode * root,TreeNode* node){
if(root == NULL || node == NULL){
return root;
}
if(node->val < root->val){
root->left = remove(root->left,node);
if(tree_height(root->right) - tree_height(root->left) == 2){
if(tree_height(root->right->left)>tree_height(root->right->right)){
root = RL(root);
}else{
root = RR(root);
}
}
}else if(node->val > root->val){
root->right = remove(root->right,node);
if(tree_height(root->left) - tree_height(root->right) == 2){
if(tree_height(root->left->left)>tree_height(root->left->right)){
root = LL(root);
}else{
root = LR(root);
}
}
}else{
if(root->left && root->right){
if(tree_height(root->left) >tree_height(root->right)){
// 左边>右边,替换左边的最大的,删除最大的
TreeNode * maxnode = _max_node(root->left);
root->val = maxnode->val;
root->left = remove(root->left,maxnode);
}else{
// 左边<右边,替换右边的最小的,删除最小的
TreeNode * minnode = _min_node(root->right);
root->val = minnode->val;
root->right = remove(root->right,minnode);
}
}else{
// 直接删除
TreeNode * tmp = root;
root = root->left?root->left:root->right;
delete tmp;
}
}
return root;
}
int AVL::remove(T val){
TreeNode*node = search(val);
remove(this->root,node);
return 0;
}
析构
只建立,不释放内存是会造成内存泄漏的,因此析构是必不可少的。这里使用后序遍历的方式析构,先释放左右节点,在释放根节点。
void AVL::_del(TreeNode * root){
if(root!=NULL){
if(root->left == NULL && root->right == NULL){
delete root;
return;
}else{
_del(root->left);
_del(root->right);
delete root;
}
}
}
完整代码
https://github.com/mrcat2018/blog/blob/src/src/%E5%9F%BA%E7%A1%80%E7%BB%83%E4%B9%A0/%E6%A0%91/%E5%B9%B3%E8%A1%A1%E6%A0%91.cpp
点这里
参考
https://en.wikipedia.org/wiki/AVL_tree
http://www.cnblogs.com/skywang12345/p/3577360.html