AVL添加
平衡二叉树,是一种二叉排序树,其中每个结点的左子树和右子树的高度差至多等于1。
它是一种高度平衡的二叉排序树。现二叉平衡树结点定义如下:
typedef struct node
{int val;struct node *left;struct node *right;struct node *parent;int height;
} node_t;
请实现平衡二叉树的插入算法:
向根为 root 的平衡二叉树插入新元素 val,成功后返回新平衡二叉树根结点
node_t *avl_insert(node_t *root, int val);#include <stdlib.h>
#include <stdio.h>
#include "avl.h"int get_height(node_t *p){if(!p)return 0;elsereturn p->height;
}
示例代码如下:
一定要超级仔细, 不然绝对后悔!
node_t* avl_insert(node_t *root, int val){
//首先清晰字母定义;
//val新插入结点元素值,height高度!!!
//定义查找过程中出现的距离插入结点最近的平衡因子不为零的结点A
//定义A的孩子结点为B,需要旋转的结点
//定义插入节点为s,s的值为val
//平衡因子:左子树减去右子树深度 node_t *s, *A, *B, *C, *p, *fp;//依次:插入点, 失衡点(也可能是旋转点),旋转点,旋转点(也可能是插入点=s),动点,跟踪点int i, k;//平衡因子 s = (node_t *)malloc(sizeof(node_t));if(!s) return NULL;s->val = val;s->left = s->parent = s->right = NULL;s->height = 1;//类似于指针跟踪技术,p为动指针,A为跟踪指针 A = root; A->parent = NULL;p = root; p->parent = NULL;//找出A if(!p)root = s;else{while(p){//先找出最近的A->height!=0的结点, 就是最后的失衡点i = get_height(p->left) - get_height(p->right); if(i){A = p;A->parent = p->parent;}//fp跟踪p,因为下一步p会往下移动,p最终指向s的那一层 fp = p;if(val < p->val)p = p->left;elsep = p->right;}//p最终指向NULL就推出循环 } //插入, 此时fp是p的前一个结点,p指向空 if(val < fp->val)fp->left = s;elsefp->right = s;//确定旋转结点B,修改A的平衡因子if(val < A->val)B = A->left;elseB = A->right;A->height++;//修改路径B到s的高度, B在A的下一层 p = B; // p最终指向s, 之前指向的是s这一层,但是是空while(p != s){p->height++;if(val < p->val)p = p->left; elsep = p->right; }//最终s的高度没有++的 //调整完高度就修改结点和指针, 首先需要判断失衡类型//分为LL,LR,RR,RL//结点A,B平衡因子在修改指针的过程中会变化,但是路径上的结点不会//指针修改包括s结点指针和原来双亲结点指针 i = get_height(A->left) - get_height(A->right);k = get_height(B->left) - get_height(B->right); if(i == 2 && k == 1){//LL//B作为旋转结点//先改结点指针, 此时s插入在B的左子树下, 原来可以认为B左右子树,A右子树均为空A->left = B->right;B->right = A;//考虑原来A结点的指针,改成B后相应的指针也要改变,下面同理if(A->parent == NULL)root = B;else if(A->parent->left == A)A->parent->left = B;elseA->parent->right = B; }else if(i == -2 && k == -1){//RRA->right = B->left;B->left = A;if(A->parent == NULL)root = B;else if(A->parent->left == A)A->parent->left = B;elseA->parent->right = B; }else if(i == 2 && k == -1){//LR//此时认为C的左右子树空,B逆时针旋转,A顺时针旋转, s插入C的左子树或者右子树 //如果C结点也是空,也就是说B右子树空,那么直接插入C=s为B右子树,此时A右子树也是空的 C = B->right;B->right = C->left;A->left = C->right;C->left = B;C->right = A;if(A->parent == NULL)root = C;else if(A->parent->left == A)A->parent->left = C;elseA->parent->right = C;}else if(i == -2 && k == 1){//RL //和LR一样,画图来看就好C = B->left;A->right = C->left;B->left = C->right;C->left = A;C->right = B;if(A->parent == NULL)root = C;else if(A->parent->left == A)A->parent->left = C;elseA->parent->right = C;}return root;
}