数据结构 编程1年新手视角的平衡二叉树AVL从C与C++实现①

平衡二叉树是一种特化的二叉树,为纪念提出者Adelse-Velskil和Landis,因此也称AVL树。

为什么说它是特化的,特化体现在哪里呢?

平衡二叉树的平衡体现在,它的每个结点的左子树left和右子树right的高度height永远相差不超过1,换句话说,就是可以左边比右边高1,或者右边比左边高1,最好是两侧是同高(有利于检索数据时复杂度保持最低,从树另一个角度看是保证了两边吸收阳光光合作用营养均衡 :)

可以证明,由于平衡因子的存在,搜索复杂度保持在O(log N)。

那么我们首先可以直观地写出如下两个函数,getHeight和getBalance

int getHeight(结点)

{

        return 结点的height;

}

int getBalance(左子树, 右子树)  

{

        return getHeight(左子树) - getHeight(右子树);  //这个的绝对值后面要用来与1比大小

}

好了,那么我们的结点就很直观知道需要至少有这些结构成员:结点存放的数据值,结点的高度,结点所指的左子树,结点所指的右子树。

typedef struct node{

        int value;

        int height;

        struct node*left;  //左右子树用结构指针,递归定义左右子树的结点也有着同样的结构成员

        struct node*right;

}node;

以上是C语言版本,若C++可以简化为以下:

struct node{

        int value;

        int height;

        node*left;

        node*right;

};

有了树的结构,那么我们来建立第一棵树,假设在树中存入的数据值value:

node*newNode(int value){

        node*nNode = (node*)malloc(sizeof(node));  // 若C++赋值右边改为 = new node

        nNode->value = value;

        nNode->height = 1;

        nNode->left = nNode->right = NULL;  

        return nNode;

}

这样我们可以把最开始定义的getHeight和getBalance更新为

int getHeight(node*node){

        if(node==NULL) return 0;

        else return node->height;

}

int getBalance(node*node){

        return getHeight(node->left) - getHeight(node->right);

}

而树是会不断长高的(数据不断插入)那么我们也需要定义一个更新树高的函数,树高=从根结点root的左子树或右子树比较,取高的getHeight,然后加上根结点那段高度+1

int max(int a, int b){   //若C++可调用max不须写这个

        return (a>b)?a:b;

}

int getUpdateHeight(node*node){

        return 1+max(getHeight(node->left), getHeight(node->right));

}

那么,以上部分就是AVL的整体框架,接下来是针对它特化操作而准备的。为了保持平衡,在数据插入时很直观地可想到,如果每次直接从子树添加,会破坏本身平衡,也就是说,在数据插入时,结点之间的移位rotate是免不了的。

可以总结出来,在如一“撇”“丿"的形状下(即根-左子树L-左子树L)插入新数据,要保持或还原为 ” ^ "的形状,必须将上端往右下方弯折rightRotate。

同理,如一“捺” “\”的形状下(即根-右子树R-右子树R)插入新数据,要保持或还原为 ” ^ "的形状,必须将上端往左下方弯折leftRotate。

由此,我们可以写出LL型对应的rightRotate右旋;RR型对应的leftRotate左旋函数;

node* rightRotate(node*root){

        node*newRoot = root->left;  /* 原root的左子树担任新root,准备把原root弯下来作为新root的右子树,但是如果新root本身已经有右子树冲突怎么办(园艺上是重叠枝)要把它剪下来嫁接到原root做左子树(高度低了一层)如果有人说那原root如果也有左子树冲突了怎么办,没错原root肯定有左子树,但仔细发现已经不在了,在哪里?*/

        root->left = newRoot->right; // 如newRoot无右子树即NULL也是可以的

        newRoot->right = root;

        root->height = getUpdateHeight(root);  // 换位置后更新高度

        newRoot->height = getUpdateHeight(newRoot);

        return newRoot;

}

对应地,我们可以写出左旋

node* leftRotate(node*root){

        node*newRoot = root->right;

        root->right = newRoot->left;

        newRoot->left = root;

        root->height = getUpdateHeight(root);

        newRoot->height = getUpdateHeight(newRoot);

        return newRoot;

}

有了以上对数据的操作,接下来,就是综合起来做数据的插入

你可能感兴趣的:(数据结构,c语言,c++,算法)