C++实现AVL树的完整代码

实现AVL树的完整代码需要遵循以下步骤:

第一步:头文件声明

在代码文件的开头,我们需要声明头文件,以引入所需的库和类。在实现AVL树的完整代码中,我们需要添加以下头文件:

#include <iostream>
#include <algorithm>

这里用到了C++标准库中的iostream库,用于输入输出操作,以及algorithm库,它包含了各种有用的算法,包括二叉搜索树中需要用到的max()和min()函数。

第二步:定义AVL树结构

在C++中,我们可以使用结构体来定义AVL树的节点结构。在实现AVL树的完整代码中,我们需要声明以下结构体:

struct node {
    int key;
    struct node *left;
    struct node *right;
    int height;
};

这里声明了一个结构体node,其中包含了四个成员,分别是节点的值key,左子树指针left,右子树指针right,以及节点的高度height。其中,左右子树指针可以指向其他node结构体,形成树状结构。

第三步:定义基本操作函数

接下来,我们需要定义AVL树的基本操作函数。在实现AVL树的完整代码中,我们需要定义以下函数:

1. 计算节点高度

int height(struct node *N) {
    if (N == NULL)
        return 0;
    return N->height;
}

这里定义了一个计算节点高度的函数,它采用了递归的方法计算节点的高度。如果节点为空,则返回0;否则,返回节点的高度。

2. 求最大值和最小值

int max(int a, int b) {
    return (a > b) ? a : b;
}

int min(int a, int b) {
    return (a < b) ? a : b;
}

这里定义了求最大值和最小值的函数,它们采用了三目运算符,判断a和b的大小关系,返回较大或较小的值。

3. 新建节点

struct node* newNode(int key) {
    struct node* node = new struct node;
    node->key = key;
    node->left = NULL;
    node->right = NULL;
    node->height = 1;
    return(node);
}

这里定义了新建节点的函数,它创建一个新的node结构体,设置节点值为key,左右子树指针为NULL,高度为1,然后返回该节点。

4. 右旋函数

struct node* rightRotate(struct node* y) {
    struct node* x = y->left;
    struct node* T2 = x->right;
    x->right = y;
    y->left = T2;
    y->height = max(height(y->left), height(y->right)) + 1;
    x->height = max(height(x->left), height(x->right)) + 1;
    return x;
}

这里定义了右旋函数,它是AVL树中用于调整平衡的基本操作之一。右旋操作的目的是将左子树的较大节点上移一级,并且将原来的根节点下移一级作为右子树的节点。在右旋函数中,我们首先定义一个新的结构体x,它表示当前节点的左子节点。然后,我们将x的右子节点T2指向y的左子节点,将y的左节点指向x的右子节点T2。接下来,我们根据y和x的左右子节点的高度,重新计算y和x的高度,并将x作为新的根节点返回。

5. 左旋函数

struct node* leftRotate(struct node* x) {
    struct node* y = x->right;
    struct node* T2 = y->left;
    y->left = x;
    x->right = T2;
    x->height = max(height(x->left), height(x->right)) + 1;
    y->height = max(height(y->left), height(y->right)) + 1;
    return y;
}

这里定义了左旋函数,它与右旋函数实现的操作相反。在左旋函数中,我们首先定义一个新的结构体y,它表示当前节点的右子节点。然后,我们将y的左子节点T2指向x的右子节点,将x的右子节点指向y的左子节点T2。接下来,我们根据x和y的左右子节点的高度,重新计算x和y的高度,并将y作为新的根节点返回。

6. 获取平衡因子

int getBalance(struct node* N) {
    if (N == NULL)
        return 0;
    return height(N->left) - height(N->right);
}

这里定义了获取平衡因子的函数,它计算节点的左子树高度和右子树高度的差值,并返回该值作为平衡因子。

7. 插入节点函数

struct node* insert(struct node* node, int key) {
    if (node == NULL)
        return(newNode(key));
    if (key < node->key)
        node->left = insert(node->left, key);
    else if (key > node->key)
        node->right = insert(node->right, key);
    else
        return node;
    node->height = 1 + max(height(node->left), height(node->right));
    int balance = getBalance(node);
    if (balance > 1 && key < node->left->key)
        return rightRotate(node);
    if (balance < -1 && key > node->right->key)
        return leftRotate(node);
    if (balance > 1 && key > node->left->key) {
        node->left = leftRotate(node->left);
        return rightRotate(node);
    }
    if (balance < -1 && key < node->right->key) {
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }
    return node;
}

这里定义了插入节点的函数,它采用了递归的方式。如果节点为空,则返回新建的节点;否则,如果关键字小于当前节点的关键字,则递归插入到左子树;如果关键字大于当前节点的关键字,则递归插入到右子树。然后,更新当前节点的高度,计算平衡因子,并依据平衡因子的值旋转子树,实现平衡。

第四步:测试示例

下面是两个测试示例。

示例1:插入节点

int main() {
    struct node *root = NULL;
    root = insert(root, 10);
    root = insert(root, 20);
    root = insert(root, 30);
    root = insert(root, 40);
    root = insert(root, 50);
    root = insert(root, 25);
    return 0;
}

在这个测试示例中,我们依次插入了6个节点,其中50为根节点,30和40为左子树,10和20为左子树的左子树,25为左子树的右子树。插入过程中,程序将自动调整AVL树中各个节点的高度,保持树的平衡。

示例2:输出节点

void preOrder(struct node *root) {
    if (root != NULL) {
        std::cout << root->key << " ";
        preOrder(root->left);
        preOrder(root->right);
    }
    return;
}

int main() {
    struct node *root = NULL;
    root = insert(root, 10);
    root = insert(root, 20);
    root = insert(root, 30);
    root = insert(root, 40);
    root = insert(root, 50);
    root = insert(root, 25);
    std::cout << "Preorder traversal of the constructed AVL tree is \n";
    preOrder(root);
    return 0;
}

在这个测试示例中,我们首先定义了一个输出节点的函数preOrder,在遍历过程中先输出当前节点,然后递归遍历左子树和右子树。然后,我们依然插入了6个节点,并调用preOrder函数输出所有节点的值。输出结果如下:

Preorder traversal of the constructed AVL tree is 
30 20 10 25 50 40 

可以看出,preOrder函数按照前序遍历的顺序输出了所有节点的值,验证了AVL树的正确性。

至此,我们完成了C++实现AVL树的完整代码。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++实现AVL树的完整代码 - Python技术站

(0)
上一篇 2023年5月24日
下一篇 2023年5月24日

相关文章

  • C++实现对RGB图片进行编码的示例代码

    首先,对于RGB图片的编码,我们需要将RGB颜色空间中的每个像素点转换为对应的YUV颜色空间中的亮度值Y和色度值U、V。这一步可以通过计算公式进行:Y = 0.299R + 0.587G + 0.114B,U = 0.492(B – Y),V = 0.877(R – Y),其中R、G、B分别是像素点在RGB颜色空间中的红、绿、蓝值。 示例代码1:将RGB图片…

    C 2023年5月24日
    00
  • 如何修复0xc000007b?win7/win10一键修复0xc000007b的方法

    下面是详细讲解 “如何修复0xc000007b?win7/win10一键修复0xc000007b的方法” 的完整攻略: 1. 什么是0xc000007b错误? 0xc000007b是Windows操作系统中常见的错误代码之一,表示应用程序无法正常启动。通常发生在程序启动时,弹出一个错误窗口,提示“应用程序无法正常启动,错误代码为0xc000007b”。 2.…

    C 2023年5月23日
    00
  • VScode配置C语言环境完整版(亲测可用)

    以下是“VScode配置C语言环境完整版(亲测可用)”的完整攻略: 步骤一:安装MinGW编译器 访问MinGW官网(https://sourceforge.net/projects/mingw-w64/),下载适合自己操作系统版本的MinGW编译器安装程序,并进行安装。 打开安装目录下的bin文件夹,并将其中的mingw32-make.exe、gcc.ex…

    C 2023年5月23日
    00
  • 浅要分析Python程序与C程序的结合使用

    浅要分析Python程序与C程序的结合使用 Python和C都是广泛使用的编程语言。尽管二者有着不同的特性,但它们在很多方面都可以相互配合,实现更复杂的应用程序。 为什么要结合使用Python和C? 有时候,我们可能需要利用Python的高级特性来快速开发程序,同时又需要用C来编写一些对性能要求比较高的关键部分。 Python在高级特性和易于编写方面有着明显…

    C 2023年5月30日
    00
  • Python类的继承super相关原理解析

    Python中的类可以通过继承来扩展父类的功能。而在子类中,我们通常需要调用父类中的方法或属性来实现一些特定的功能,这时候就需要用到super()函数来实现。本篇文章将对Python类的继承与super()函数进行详细讲解。 Python类的继承 Python中的类继承是一种重要的面向对象编程思想中的体现,它允许我们在已有的类的基础上创建新的类,同时不破坏原…

    C 2023年5月23日
    00
  • C++定时器Timer在项目中的使用方法

    下面是“C++定时器Timer在项目中的使用方法”的攻略。 1. Timer类和定时器的原理 首先,要使用C++定时器,我们需要了解Timer类以及定时器的原理。Timer类实现了简单的定时器功能。它内部使用了C++11的库,通过高精度计时来实现定时器的功能。定时器的原理是:在一定时间间隔之后执行一个任务,而这个任务可以是一个函数,一个类的成员函数,或者一个…

    C 2023年5月23日
    00
  • C++初识类和对象

    C++初识类和对象 什么是类和对象? 在C++中,类和对象是两个重要概念,类是一种用户自定义的数据类型,它是一组数据和操作数据的函数的集合,而对象是类的一个实例,是具体的、有形的存在。可以通过对象来使用类中的函数和数据。 如何定义一个类? 定义一个类,需要使用关键字class,语法如下: class 类名 { public: // 公共成员函数和成员变量 p…

    C 2023年5月22日
    00
  • C语言的动态内存管理你了解吗

    C语言的动态内存管理是非常重要的知识点,掌握了动态内存管理,可以更好地理解程序的运行过程。下面是动态内存管理的完整攻略: 1. 动态内存分配的概念 动态内存分配是在程序运行时向操作系统申请内存空间,对内存进行分配、释放和管理的过程。与静态内存分配不同,静态内存分配在程序编译时就已经确定了。动态内存分配通常用于需要运行时才完成大小和数量的确定的情况下,例如输入…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部