二叉搜索树和平衡树

1.二叉搜索树(BST)

二叉搜索树(Binary Search Tree),也有称之为二叉排序树、二叉查找树

1.1定义和性质

在二叉树的基础上,增加了几个规则约束:

  • 如果他的左⼦树不空,则左⼦树上所有结点的值均⼩于它的根结点的值。
  • 若它的右⼦树不空,则右⼦树上所有结点的值均⼤于它的根结点的值。
  • 它的左、右树⼜分为二叉排序树。

 1.2中序遍历结果

1 2 3 4 5 6 7 8 9

1.3二叉搜索树的优势

  • 二叉排序树的中序遍历,就是一个从⼩到⼤排好序的序列,但是查找时,完全没有必要先进行中序遍历生成一个有序的数组,再二分查找,直接根据二叉搜索树的约束直接操作。
  • 查找时间最坏情况就是树的深度
  • 二叉搜索树的查找逻辑,可以写成递归的思路和非递归思路。

BiTree SearchBST(BiTree T,KeyType key){

//如果递归过程中 T 为空,则查找结果,返回NULL;或者查找成功,返回指向该关键字的指针

        if (!T || key==T->data) {

                 return T;

        }else if(key<T->data){

//递归遍历其左孩⼦

                return SearchBST(T->lchild, key);

        }else{

 //递归遍历其右孩⼦

                return SearchBST(T->rchild, key);

        }

}

1.4二叉搜索树的实现

1.4.1二叉搜索树的插入操作

  • 算法思想
  1. 插入的新节点都是在叶节点位置
  2. 寻找插入节点的位置,建立父节点和新节点的左右关系
  3. 是一种递归思想
// 按照二分搜索树的规则插入数据(非递归方式)
void insertBSTreeNoRecur(BSTree *tree, Element e){
    BSNode* cur=tree->root;
    BSNode* pre= nullptr;
    //1.寻找插入新结点的位置
    while(cur){
        pre=cur;
        if(cur->data>e){
            cur=cur->left;
        }else if(cur->data<e){
            cur=cur->right;
        }else{
            return;             //存在与插入元素相同的值,直接返回
        }
    }
    // 此时,pre就是唯一知道待插入节点的前一个位置在哪里
    // 2. 分配节点
    BSNode* node= creatBSNode(e);
    // 3. 将这个新的节点,放到待插入位置前面那个节点的左或右
    // 放入pre指向结点的左或右
    if(pre){
        if(pre->data>e){
            pre->left=node;
        }else{
            pre->right=node;
        }
    }else{                  //此时树中还没有节点
        tree->root=node;
    }
    tree->count++;
}
  • 递归思路
  1. 涉及到前后节点,⼦问题就是返回新节点,上一个状态就是左⼦树还是右⼦树来接收
  • 递归核心代码
static BSNode *insertBSNodeRecur(BSTree *tree, BSNode *node, Element e){
    if(node== nullptr){
        tree->count++;
        return creatBSNode(e);
    }
    if(node->data>e){
        node->left=insertBSNodeRecur(tree,node->left,e);
    }else if(node->data<e){
        node->right=insertBSNodeRecur(tree,node->right,e);
    }

    return node;
}

1.4.2 查找某一节点下的最⼤或最⼩值

  • 算法思想
  1. 比当前节点⼩的值,一定放在他的左⼦树上,那么一直往左查找最左边的节点,就是最⼩值
  2. 比当前节点⼤的值,一定放在他的右⼦树上,那么一直往右查找最左边的节点,就是最⼤值
  • 核心代码
static void deleteMaxNode(BSNode* node){
    BSNode  *Max=node->left;                //找最大值
    BSNode *pre= node;
    while(Max&&Max->right){
        pre=Max;
        Max=Max->right;
    }
    node->data=Max->data;
    //说明找到了前驱节点,可能是node节点的左孩子,也有可能是左孩子的最右边
    if(pre->data==node->data){
        pre->left= Max->left;
    }else{
        pre->right= Max->left;
    }
    delete Max;
}

1.4.2二叉搜索树的删除操作

  • 算法分析
  1. 删除节点,共有三种可能性

叶子节点

  • 叶⼦结点从二叉搜索树中移除后,并不影响其他结点的排列规则,直接删除

度为1的结点

  • 该节点缺失左⼦树或右⼦树,当去掉这个节点后,剩余的左⼦树和右⼦树满足二叉搜索树的要求
  • 矛盾在于删除的这个节点,属于父节点的左边还是右边,那么剩余的左⼦树或右⼦树仍然满足父节点的左右属性,接入这个父节点就可以

度为2的节点

  • 假设要删除的节点A,他的后结点,既有⼤于他的也有⼩于他的,现在就是要选择一个节点B,满足左边节点都比B ⼩,右边节点都比B⼤。
  • 其实就是中序遍历时,前一个节点或后一个节点来替换这个节点,然后删除前一个或后一个节点

先找到这个待删除结点的前一个或后一个,替换待删除结点

1234567
1234457

这个时候删除4就可以,而4一定是叶⼦结点,就⼜回到了叶⼦节点删除的逻辑

  • 递归思路
  • 二叉搜索树删除情况
  1. 删除叶⼦节点,直接删除
  2. 删除的节点有一个叶⼦节点,用⼦节点来替代
  3. 删除的节点有两个⼦节点
  4. 找到前驱节点,复制前驱节点的值覆盖掉预备删除的节点,然后删除前驱节点
  5. 找到后继节点,复制后继节点的值覆盖掉预备删除的节点,然后删除后继节点
//BSearch.h

#ifndef DATA_STRUCTURE_BSEARCHTREE_H
#define DATA_STRUCTURE_BSEARCHTREE_H
typedef int  Element;
//二叉搜索树的节点,和普通二叉树没有什么区别
typedef struct bsNode{
    Element data;
    bsNode* left;
    bsNode* right;
}BSNode;
//二叉搜索树的结构
typedef struct {
    BSNode* root;       //搜索树的根节点
    int count;          //搜索树的元素
}BSTree;

//创建BSTree的结构
BSTree* createBSTree();
// 释放BSTree及树中所有结点
void releaseBSTree(BSTree *tree);

// 中序遍历
void inOrderBSTree(BSTree *tree);
void visitBSNode(BSNode *node);

// 按照二分搜索树的规则插入数据(非递归方式)
void insertBSTreeNoRecur(BSTree *tree, Element e);
// 按照二分搜索树的规则插入数据(递归方式)
void insertBSTreeRecur(BSTree *tree, Element e);
// 在二分搜索树中,查找值为e的节点
BSNode *searchBSTree(BSTree *tree, Element e);
// 计算树的高度
int heightBSNode(BSNode *node);
// 删除二叉搜索树的某个值的节点(非递归方式)
void deleteBSTreeNoRecur(BSTree *tree, Element e);
// 删除二叉搜索树的某个值的节点(递归方式)
void deleteBSTreeRecur(BSTree *tree, Element e);

#endif //DATA_STRUCTURE_BSEARCHTREE_H
//BSearch.cpp
#include<iostream>
#include "BSearchTree.h"
//创建BSTree的结构
BSTree* createBSTree(){
    BSTree *tree=new BSTree ;
    tree->root= nullptr;
    tree->count=0;
    return tree;
}
// 后序遍历方式释放BSTree及树中所有结点
static void deleteNode(BSTree *tree,BSNode* node){
    if(node){
        deleteNode(tree,node->left);
        deleteNode(tree,node->right);
        delete node;
        tree->count--;
    }
}
void releaseBSTree(BSTree *tree){
    if(tree){
        //先释放所有书中的节点
        deleteNode(tree,tree->root);
        std::cout<<"还有"<<tree->count<<"个节点"<<std::endl;
        //再释放树的结构
        delete tree;
    }
}
void visitBSNode(BSNode *node){
    std::cout<<node->data<<'\t';
}
static void inOrde(BSNode* node){
    if(node){
        inOrde(node->left);
        visitBSNode(node);
        inOrde(node->right);
    }
}
void inOrderBSTree(BSTree *tree){
    if(tree){
        inOrde(tree->root);
    }
}



//创建新节点
static BSNode* createBSNode(Element e){
    BSNode *node=new BSNode ;
    node->data=e;
    node->right=node->left= nullptr;
    return  node;
}
// 按照二分搜索树的规则插入数据(非递归方式)
void insertBSTreeNoRecur(BSTree *tree, Element e){
    BSNode* cur=tree->root;
    BSNode* pre= nullptr;
    //1.寻找插入新结点的位置
    while(cur){
        pre=cur;
        if(cur->data>e){
            cur=cur->left;
        }else if(cur->data<e){
            cur=cur->right;
        }else{
            return;             //存在与插入元素相同的值,直接返回
        }
    }
    // 此时,pre就是唯一知道待插入节点的前一个位置在哪里
    // 2. 分配节点
    BSNode* node= createBSNode(e);
    // 3. 将这个新的节点,放到待插入位置前面那个节点的左或右
    // 放入pre指向结点的左或右
    if(pre){
        if(pre->data>e){
            pre->left=node;
        }else{
            pre->right=node;
        }
    }else{                  //此时树中还没有节点
        tree->root=node;
    }
    tree->count++;
}
static BSNode *insertBSNodeRecur(BSTree *tree, BSNode *node, Element e){
    if(node == nullptr){
        tree->count++;
        return createBSNode(e);
    }
    if (e < node->data) {
        node->left = insertBSNodeRecur(tree, node->left, e);
    } else if (e > node->data) {
        node->right = insertBSNodeRecur(tree, node->right, e);
    }
    return node;
}
// 按照二分搜索树的规则插入数据(递归方式)
void insertBSTreeRecur(BSTree *tree, Element e){
    tree->root= insertBSNodeRecur(tree,tree->root,e);
}
// 在二分搜索树中,查找值为e的节点
BSNode *searchBSTree(BSTree *tree, Element e){
    if(tree){
        BSNode* node=tree->root;
        while(node){
            if(node->data>e){
                node=node->left;
            }else if(node->data<e){
                node=node->right;
            }else if (node->data == e) {
                return node;
            }

        }
    }
    return nullptr;
}
// 计算树的高度
int heightBSNode(BSNode *node){
    if(node== nullptr){
        return 0;
    }
    int leftHeight= heightBSNode(node->left);
    int rightHeight= heightBSNode(node->right);
    if(leftHeight>rightHeight){
        return ++leftHeight;
    }else{
        return ++rightHeight;
    }
}
static void deleteMaxNode(BSNode* node){
    BSNode  *Max=node->left;                //找最大值
    BSNode *pre= node;
    while(Max&&Max->right){
        pre=Max;
        Max=Max->right;
    }
    node->data=Max->data;
    //说明找到了前驱节点,可能是node节点的左孩子,也有可能是左孩子的最右边
    if(pre->data==node->data){
        pre->left= Max->left;
    }else{
        pre->right= Max->left;
    }
    delete Max;
}

/* 1. 找到这个待删除的节点node,还需要一个pre节点指向上一个位置
* 2. 判断node的度的情况
* */
void deleteBSTreeNoRecur(BSTree *tree, Element e){
    //1.找到元素
    BSNode *node=tree->root;
    BSNode *pre= nullptr;
    BSNode *tmp= nullptr;
    while(node){
        if(node->data>e){
            pre=node;
            node=node->left;
        }else if(node->data<e){
            pre=node;
            node=node->right;
        }else{
            break;
        }
    }
    //2.找到node,删除节点是非根节点
    if(pre&&node){
        //2.1判断node的度的情况
        if(node->left== nullptr){           //度为0或为1
            tmp=node->right;
        }else if(node->right== nullptr){    //度为1
            tmp=node->left;
        }else{                              //度为2的情况,从node节点中找前驱,然后进行删除
            deleteMaxNode(node);
            tree->count--;
            return;
        }
        if(node->data<pre->data){
            pre->left=tmp;
        }else{
            pre->right=tmp;
        }
        delete node;
        tree->count--;
        return;
    }
    //如果删除的是根节点
    if(pre== nullptr){
        deleteMaxNode(node);
        tree->count--;
    }
}
//找前继节点的办法
static BSNode *maxValueBSNode(BSNode *node){
    while(node&&node->right){
        node=node->right;
    }
    return node;
}

static BSNode *deleteBSNode(BSTree *tree, BSNode *node, Element e){
    if(node== nullptr){
        return nullptr;
    }
    if(e<node->data){
        node->left= deleteBSNode(tree,node->left,e);
    }else if(e>node->data){
        node->right= deleteBSNode(tree,node->right,e);
    }else{              //找到e
        BSNode *tmp;
        if(node->left== nullptr){
            tmp=node->right;
            delete node;
            tree->count--;
            return tmp;
        }
        if(node->right== nullptr){
            tmp=node->left;
            delete node;
            tree->count--;
            return tmp;
        }
        //度为2,删除度为2的节点,变成找到他的前继节点,将前继节点的值拷贝给度为2的点
        //把删除任务,转换为删除前继节点
        tmp= maxValueBSNode(node->left);
        node->data=tmp->data;
        node->left= deleteBSNode(tree,node->left,tmp->data);
    }
    return node;
}

// 删除二叉搜索树的某个值的节点(递归方式)
void deleteBSTreeRecur(BSTree *tree, Element e){
    if (tree) {
        tree->root = deleteBSNode(tree, tree->root, e);
    }
}
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include "BSearchTree.h"
// 1. 普通二叉搜索树测试
void test01() {
    Element data[] = {55, 33, 45, 100,
                      22, 80, 8, 130, 120};
    BSTree *tree = createBSTree();
    if (tree == NULL) {
        return;
    }
    // 插入元素
    for (int i = 0; i < sizeof(data) / sizeof(data[0]); ++i) {
        //insertBSTreeNoRecur(tree, data[i]);
        insertBSTreeRecur(tree, data[i]);
    }
    printf("二分搜索树的中序遍历:");
    inOrderBSTree(tree);
    printf("\n");
    int h = heightBSNode(tree->root);
    printf("高度: %d\n", h);
    releaseBSTree(tree);
}
// 二分搜索树的测试
void binarySearchFindTest(BSTree *tree, int cnt, Element value) {
    BSNode *node = NULL;
    for (int i = 0; i < cnt; ++i) {
        node = searchBSTree(tree, value);
        if (node) {
            printf("!!!BST Find!!!\n");
            return;
        }
    }
}
// 线性查找,测试次数cnt
void linearFindTest(Element *data, int n, int cnt, Element value) {
    for (int i = 0; i < cnt; ++i) {
        for (int j = 0; j < n; ++j) {
            if (data[j] == value) {
                printf("!!! Linear Find !!!");
                return;
            }
        }
    }
}
/* 顺序表和二分搜索树的查找效率
 * 随机生成n个数字,范围在1~m之间,然后测试查找m+1(找不到),模拟了最坏的情况
 * 根据运行的时间,来验证线性查找和二分搜索树查找的效率
 * */
void test02() {
    int n = 10000;
    Element m = n + 5000;
    int cnt = 10000;
    clock_t start, end;			// 系统滴答数
    // 创建n个元素,取值范围在1-m
    Element *data = (Element *) malloc(sizeof(Element) * n);
    srand(time(NULL));
    for (int i = 0; i < n; ++i) {
        data[i] = rand() % m + 1;
    }
    // 测试线性查找的时间
    start = clock();
    linearFindTest(data, n, cnt, m + 10);
    end = clock();
    printf("线性查找耗时: %f.\n", (double )(end - start) / CLOCKS_PER_SEC);
    // 测试二分搜索树的查找时间消耗
    BSTree *tree = createBSTree();
    for (int i = 0; i < n; ++i) {
        insertBSTreeNoRecur(tree, data[i]);
    }
    start = clock();
    binarySearchFindTest(tree, cnt, m + 10);
    end = clock();
    printf("二分搜索树查找耗时: %f.\n", (double )(end - start) / CLOCKS_PER_SEC);
    releaseBSTree(tree);
    free(data);
}

void test03() {
    Element data[] = {55, 33, 45, 100,
                      22, 80, 8, 130, 120};
    BSTree *tree = createBSTree();
    if (tree == NULL) {
        return;
    }
    // 插入元素
    for (int i = 0; i < sizeof(data) / sizeof(data[0]); ++i) {
        insertBSTreeNoRecur(tree, data[i]);
    }
    printf("二分搜索树的中序遍历:");
    inOrderBSTree(tree);
    printf("\n");
    printf("删除8节点\n");
    // deleteBSTreeNoRecur(tree, 55);
    deleteBSTreeRecur(tree, 55);
    printf("二分搜索树的中序遍历:");
    inOrderBSTree(tree);
    printf("\n");
    releaseBSTree(tree);
}

int main() {
    test01();
    return 0;
}

2.二叉平衡树

AVL树是最早被发明的⾃平衡二叉查找树。在AVL树中,任一节点对应的两棵⼦树的最⼤⾼度差的绝对值为1,因 此它也被称为⾼度平衡树。AVL树是根据它的发明者G.M. Adelson-Velsky和E.M. Landis命名的。

查找、插入和删除在平均和最坏情况下的时间复杂度都是 O(logn)。增加和删除元素的操作则可能需要借由一次 或多次树旋转,以实现树的重新平衡。

BST 二叉树的基础上,增加左小右大的规则

AVL BST树基础上,增加每个节点的平衡因子要满足

        优点:接近完全二叉树的高度,查找效率O(lognN)

        缺点:插入、删除会引起大量的节点变化

红黑树:平衡 解决了AVL中插入、删除效率不高、降低了查找效率。

2.1二叉搜索树的问题

  • 二叉搜索树的查找效率取决于树的⾼度,因此保持树的⾼度最⼩,即可保证树的查找效率。
  • 二叉搜索树会退化成单链表,搜索效率降低为O(n)

二叉搜索树一定程度上可以提⾼搜索效率,但是当原序列有序时,例如序列 A = {1,2,3,4, 5,6},构造二叉 搜索树如图。依据此序列构造的二叉搜索树为右斜树,同时二叉树退化成单链表,搜索效率降低为 O(n)。

二叉搜索树的查找效率取决于树的⾼度,因此保持树的⾼度最⼩,即可保证树的查找效率。

2.2平衡因子

左⼦树与右⼦树的⾼度差即为该节点的平衡因⼦(BF,Balance Factor)

平衡二叉树中不存在平衡因⼦⼤于 1 的节点。

在一棵平衡二叉树中,节点的平衡因⼦只能取 0 、1 或者 -1 ,分别对应着左右⼦树等⾼,左⼦树比较⾼,右⼦树比较⾼。

2.3 平衡树失衡情况分析

2.3.1 左旋

当加入一个新节点后,右边的⾼度增加,导致失衡

 2.3.2 右旋

/* 右旋操作

*         py

*         |

*         y

*         / \

*       x  ry

*      / \

*    lx  rx

* */ AVLNode *rightRotate(AVLNode *y);

2.3.3 LL、RR、LR、RL

  • LL :失衡节点左边⾼,新插入节点是在失衡节点左孩⼦的左边。直接对失衡节点进行右旋。
  • RR:失衡节点右边⾼,新插入节点是在失衡节点右孩⼦的右边。直接对失衡节点进行左旋。
  • LR:失衡节点左边⾼,新插入节点是在失衡节点左孩⼦的右边。先对左孩⼦进行左旋,再对失衡节点进行右旋。
  • RL:失衡节点右边⾼,新插入节点是在失衡节点右孩⼦的左边。先对右孩⼦进行右旋,再对失衡节点进行左旋。

2.4 平衡二叉树的插入操作

  • 算法思路
  1. 先找到要插入的节点位置,插入新节点
  2. 更新平衡因⼦,根据平衡因⼦⼩于-1和⼤于1的情况进行讨论

 2.5平衡二叉树的删除操作

  • 算法思路
  1. 依据二叉排序树的删除特点,依然按照3种条件进行删除,保证最后删除的都是叶⼦节点即可。
  2. 节点删除后,依次对节点进行平衡因⼦检查,若发现某节点不平衡,按照平衡调节法进行调节。
#ifndef AVL_TREE_H
#define AVL_TREE_H
#include <stdio.h>
#include <stdlib.h>
typedef int Element;
// 定义平衡二叉树的节点结构
typedef struct AVLNode {
	Element data;
	struct AVLNode *left;
	struct AVLNode *right;
	int height;				// 每个节点的高度
}AVLNode;
// 平衡二叉树的结构
typedef struct {
	AVLNode *root;
	int count;
}AVLTree;

AVLTree *createAVLTree();				// 产生平衡二叉树
void releaseAVLTree(AVLTree *tree);		// 释放平衡二叉树
void visitAVLNode(AVLNode *node);		// 访问平衡二叉树的节点
void inOrderAVLTree(AVLTree *tree);		// 平衡二叉树的中序遍历

// 插入元素到AVL树
void insertAVLTree(AVLTree *tree, Element e);
// 从AVL树中删除元素
void deleteAVLTree(AVLTree *tree, Element e);
#endif
#include "avlTree.h"
AVLTree *createAVLTree() {
	AVLTree *tree = (AVLTree *) malloc(sizeof(AVLTree));
	if (tree == NULL) {
		fprintf(stderr, "tree malloc failed!\n");
		return NULL;
	}
	tree->count = 0;
	tree->root = NULL;
	return tree;
}

static void freeNode(AVLTree *tree, AVLNode *node) {
	if (node) {
		freeNode(tree, node->left);
		freeNode(tree, node->right);
		free(node);
		tree->count--;
	}
}

void releaseAVLTree(AVLTree *tree) {
	if (tree) {
		freeNode(tree, tree->root);			// 后序递归释放节点
		printf("AVLTree have %d node!\n", tree->count);
		free(tree);
	}
}

/* 访问平衡二叉树节点,显示内容和此节点的高度 */
void visitAVLNode(AVLNode *node) {
	if (node) {
		printf("\t<%d:%d>", node->data, node->height);
	}
}
/* 递归中序遍历 */
static void inOrderAVLNode(AVLNode *node) {
	if (node) {
		inOrderAVLNode(node->left);
		visitAVLNode(node);
		inOrderAVLNode(node->right);
	}
}

void inOrderAVLTree(AVLTree *tree) {
	if (tree) {
		inOrderAVLNode(tree->root);
		printf("\n");
	}
}

static int maxNum(int a, int b) {
	return (a > b) ? a : b;
}
static int h(AVLNode *node) {
	if (node == NULL)
		return 0;
	else
		return node->height;
}
/* 左旋操作
 *     px
 *     |
 *     x
 *   /  \
 * lx    y
 *      / \
 *     ly ry
 * */
static AVLNode *leftRotate(AVLNode *x) {
	AVLNode *y = x->right;
	x->right = y->left;
	y->left = x;
	// 因为是平衡树,要更新x y的高度
	x->height = maxNum(h(x->left), h(x->right)) + 1;
	y->height = maxNum(h(y->left), h(y->right)) + 1;
	return y;
}

/* 右旋操作
 *       py
 *       |
 *       y
 *     /  \
 *    x   ry
 *   / \
 * lx  rx
 * */
AVLNode *rightRotate(AVLNode *y) {
	AVLNode *x = y->left;
	y->left = x->right;
	x->right = y;
	x->height = maxNum(h(x->left), h(x->right)) + 1;
	y->height = maxNum(h(y->left), h(y->right)) + 1;
	return x;
}

static int getBalance(AVLNode *node) {
	if (node == NULL)
		return 0;
	return h(node->left) - h(node->right);
}

static AVLNode *createAVLNode(Element e) {
	AVLNode *node = (AVLNode *) malloc(sizeof(AVLNode));
	if (node == NULL) {
		return NULL;
	}
	node->left = node->right = NULL;
	node->height = 1;
	node->data = e;
	return node;
}

static AVLNode *insertAVLNode(AVLTree *tree, AVLNode *node, Element e) {
	if (node == NULL) {		// 递归中递的边界条件
		tree->count++;
		return createAVLNode(e);
	}
	// 1. 递归找到插入 BST
	if (e < node->data) {
		node->left = insertAVLNode(tree, node->left, e);
	} else if (e > node->data) {
		node->right = insertAVLNode(tree, node->right, e);
	} else {			// 插入的元素,已经在AVL树中存在
		return node;
	}
	// 2. 归的过程中,更新归中节点的高度
	node->height = 1 + maxNum(h(node->left), h(node->right));
	// 计算这个节点的平衡因子
	int balance = getBalance(node);
	// 3. 判断平衡因子 left - right  > 1  L   < 1 R
	// 4. 调节 ,判断LL LR   RR RL
	if (balance > 1) {			// 失衡节点的左边高度比较大		L
		// 跟失衡节点的子节点判断下一步是L还是R
		if (e > node->left->data) {		// LR
			// 把LR中 把R进行左旋,转成LL状态
			node->left = leftRotate(node->left);
		}
		return rightRotate(node);		// LL
	} else if (balance < -1) {					//  右边高度大了  R
		if (e < node->right->data) {		// L
			node->right = rightRotate(node->right);
		}
		return leftRotate(node);		// RR
	}
	return node;				// 不需要调整,直接返回这个节点(归)
}

void insertAVLTree(AVLTree *tree, Element e) {
	if (tree) {
		tree->root = insertAVLNode(tree, tree->root, e);
	}
}

static AVLNode *deleteAVLNode(AVLTree *tree, AVLNode *node, Element e) {
	AVLNode *tmp;
	if (node == NULL) {			// 递到空位置,都没有进入到else
		return NULL;
	}
	// 1. 找到要删除点,按照二分搜索树的规则,删除
	if (e < node->data) {
		node->left = deleteAVLNode(tree, node->left, e);
	} else if (e > node->data) {
		node->right = deleteAVLNode(tree, node->right, e);
	} else {		// 2. 找到了这个节点
		if (node->left == NULL || node->right == NULL) {
			tmp = node->left ? node->left : node->right;
			if (tmp == NULL) {				// 度为0,直接删除node,归NULL
				free(node);
				tree->count--;
				return NULL;
			} else {						// 度为1,本身删除node,改为删除tmp,把tmp的关系拷贝到node上
				// node->data = tmp->data;
				// node->left = tmp->left;
				// node->right = tmp->right;
				// free(tmp);
				// tree->count--;
				free(node);
				return tmp;
			}
		} else {							// 找前驱节点,然后更新这个点,转为删除前驱点
			tmp = node->left;
			while (tmp->right) {
				tmp = tmp->right;
			}
			node->data = tmp->data;
			node->left = deleteAVLNode(tree, node->left, tmp->data);
		}
	}
	// 2. 更新平衡因子
	node->height = 1 + maxNum(h(node->left), h(node->right));
	int balance = getBalance(node);
	if (balance > 1) {								// L
		if (getBalance(node->left) < 0) {	// R
			node->left = leftRotate(node->left);
		}
		return rightRotate(node);
	} else if (balance < -1) {						// R
		if (getBalance(node->right) > 0) {	// L
			node->right = rightRotate(node->right);
		}
		return leftRotate(node);
	}
	return node;
}

/* 从平衡二叉树中删除元素e
 * 1. 按照二叉搜索树的规则,递归找到元素e所在节点
 * 2. 判断这个节点的度
 * 		2.1 如果是度为1,用父节点接收存在的子树
 * 		2.2 如果是度为0,直接删除,父节点接收一个NULL指针
 * 		2.3 如果是度为2,找到这个节点的前驱或者后继节点,用这个节点的值替换度为2的点
 * 			转成删除前驱或者后继这个节点
 * 3. 归的过程中,找失衡点
 * 4. 又根据LL LR  RL RR的规则,进行旋转
 * */
void deleteAVLTree(AVLTree *tree, Element e) {
	if (tree) {
		tree->root = deleteAVLNode(tree, tree->root, e);
	}
}

#include "avlTree.h"

int main() {
	Element data[] = {10, 20, 30, 40, 
					  50, 60, 67, 80};
	AVLTree *tree = createAVLTree();
	if (tree == NULL) {
		return -1;
	}
	for (int i = 0; i < sizeof(data) / sizeof(data[0]); ++i) {
		insertAVLTree(tree, data[i]);
	}
	printf("平衡二叉树的中序遍历:");
	inOrderAVLTree(tree);
	printf("\n平衡二叉树的高度: %d\n", tree->root->height);
	deleteAVLTree(tree, 60);
	printf("平衡二叉树的中序遍历:");
	inOrderAVLTree(tree);
	printf("\n平衡二叉树的高度: %d\n", tree->root->height);
	releaseAVLTree(tree);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值