广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++数据结构之AVL树如何实现
  • 394
分享到

C++数据结构之AVL树如何实现

2023-07-02 08:07:18 394人浏览 薄情痞子
摘要

这篇文章主要讲解了“c++数据结构之AVL树如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++数据结构之AVL树如何实现”吧!1.概念(1)二叉搜索树的缺点要手撕AVL树,我们首先

这篇文章主要讲解了“c++数据结构之AVL树如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++数据结构之AVL树如何实现”吧!

1.概念

(1)二叉搜索树的缺点

要手撕AVL树,我们首先要知道什么是AVL树。AVL树是在二叉搜索树的基础之上改造的。当我们插入的是一个有序的序列的时候,二叉搜素树会使用一条直线来进行存储,这样并不利于查找。

C++数据结构之AVL树如何实现

当遇到这种情况的时候我们就需要对这棵树来进行调整。AVL树会通过旋转等操作,来规避这种情况。最终满足每一个节点的平衡因子的绝对值<=1,从而达到近似平衡的目的。

节点的平衡因子值=右子树的高度-左子树高度

(2)定义节点

在AVL树中,除了需要定义平衡因子bf之外,还需要定义指向节点父节点的指针。方便我们来进行平衡因子的更新。

struct AVLTreenode{AVLTreeNode* right;AVLTreeNode* left;AVLTreeNode* parent;pair<int, int> _kv;int _bf;AVLTreeNode(pair<int, int> kv):right(nullptr),left(nullptr),parent(nullptr),_kv(kv),_bf(0){}};

同时和map一样,我们使用pair类型来进行数据的存储。

2.插入

(1)拆分

AVL树的插入就是AVL树的精髓所在,我们在插入节点的同时还需要对平衡因子进行控制。

AVL树的插入我们可以拆分成五个函数,其中四个为旋转函数,一个为主要的插入函数。

而这个主要的插入函数,我们还可以将其分为三个部分:找节点,插节点,更新平衡因子。而更新平衡因子后就需要判断是否需要进行旋转的操作。

在进行插入之前,我们将插入的节点定义为kv。

(2)找节点与插节点

这一过程与二叉搜索树是相同的,这里就不多赘述了。二叉搜索树

直接上代码:

//初始化头结点if (_root == nullptr){_root = new Node(kv);return true;}//找到要插入节点的位置Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->left;}else{assert(false);}}//插入节点cur = new Node(kv);if (parent->_kv.first<kv.first){parent->right = cur;cur->parent = parent;}else if (parent->_kv.first>kv.first){parent->left = cur;cur->parent = parent;}else{assert(false);}

(3)更新平衡因子与旋转

更新平衡因子

每当我们插入一个节点的时候,就需要对该节点的所有父辈节点来进行平衡因子的更新。注意,当插入节点后,只有其父辈节点的平衡因子才会受到影响,而其他节点的平衡因子不会被影响。

可以根据每个节点的parent来找到其父亲节点,从而逐渐向上更新平衡因子。

当遇到以下两种情况平衡因子的更新停止。

某一父辈节点的平衡因子为0。

更新到根节点。

旋转

当更新之后的平衡因子为2或者-2的时候,不符合AVL树的平衡因子在-1~1之间的定义,此时需要发生旋转。触发旋转的条件与当前节点cur和它的parent有关。

当parent和cur的平衡因子分别为:

(1)2和1,触发左旋

void RotateL(Node* parent){Node* cur = parent->right;Node* curL = cur->left;Node* parentParent = parent->parent;parent->right = curL;if (curL)curL->parent = parent;cur->left = parent;parent->parent = cur;if (parent == _root){_root = cur;_root->parent = nullptr;}else{if (parentParent->left == parent){parentParent->left = cur;cur->parent = parentParent;}else if (parentParent->right == parent){parentParent->right = cur;cur->parent = parentParent;}else{assert(false);}}parent->_bf = 0;cur->_bf = 0;}

用一张图来表示一下这个过程:

h表示某树的高度,当在红色部分处插入一个节点时,60的平衡因子变为1,30的平衡因子变为2。

C++数据结构之AVL树如何实现

此时就需要发生旋转:

C++数据结构之AVL树如何实现

通过旋转使树重新变成一棵AVL树,整个过程分为三步:

  • 60的左子树置为30,30的右子树置为60的左子树。

  • 将30与更上层的父辈节点链接起来。

  • 将30和60的平衡因子都更新为0。

注意,由于AVL树是三叉树,因此在链接的时候需要将父节点也链接起来。因此在将60的左子树链接到30的右子树的时候,需要进行判空来避免空指针的解引用:

void RotateL(Node* parent){Node* cur = parent->right;Node* curL = cur->left;Node* parentParent = parent->parent;parent->right = curL;if (curL)curL->parent = parent;cur->left = parent;parent->parent = cur;if (parent == _root){_root = cur;_root->parent = nullptr;}else{if (parentParent->left == parent){parentParent->left = cur;cur->parent = parentParent;}else if (parentParent->right == parent){parentParent->right = cur;cur->parent = parentParent;}else{assert(false);}}parent->_bf = 0;cur->_bf = 0;}

(2)-2和-1,触发右旋

C++数据结构之AVL树如何实现

C++数据结构之AVL树如何实现

右旋同样分为三步:

  • 将30的右链接到60的左子树。将60链接到30的右。

  • 将30与上层节点链接起来。

  • 将30和60的平衡因子都更新为0。

void RotateR(Node* parent){Node* cur = parent->left;Node* curL = cur->left;Node* curR = cur->right;Node* parentParent = parent->parent;parent->left = curR;if (curR)curR->parent = parent;cur->right = parent;parent->parent = cur;if (parent == _root){    _root = cur;_root->parent = nullptr;}else{if (parentParent->left == parent){parentParent->left = cur;cur->parent = parentParent;}else if (parentParent->right == parent){parentParent->right = cur;cur->parent = parentParent;}else{assert(false);}}cur->_bf = 0;parent->_bf = 0;}

(3)-2和1,左右双旋

当为-2和1或者2和-1的时候,仅仅靠单旋是解决不了问题的,这个时候我们就需要进行双旋:

C++数据结构之AVL树如何实现

左单旋:

C++数据结构之AVL树如何实现

右单旋:

C++数据结构之AVL树如何实现

无论是在红色部分或者蓝色部分插入节点,都会导致发生左右双旋。

左右双旋分为三步:

  • 对30节点进行左单旋。

  • 对90节点进行右单旋。

  • 根据60的平衡因子来更新30和90的平衡因子:当60的平衡因子为0时,30和90的平衡因子也为0;当60的平衡因子为1时,30的平衡因子为-1,90的平衡因子为0;当60的平衡因子为-1时,30的平衡因子为0,90的平衡因子为1。

void RotateLR(Node* parent){Node* subL = parent->left;Node* subLR =subL->right;int bf = subLR->_bf;RotateL(parent->left);RotateR(parent);if (bf == 0){parent->_bf = 0;subLR->_bf = 0;subLR->_bf = 0;}else if (bf == -1){parent->_bf = 1;subL->_bf = 0;subLR->_bf = 0;}else if (bf == 1){parent->_bf = 0;subL->_bf = -1;subLR->_bf = 0;}}

(4)2和-1,右左双旋

C++数据结构之AVL树如何实现

右单旋:

C++数据结构之AVL树如何实现

左单旋:

C++数据结构之AVL树如何实现

无论是在红色部分或者蓝色部分插入节点,都会导致发生右左双旋。

右左双旋分为三步:

  • 对90节点进行右单旋。

  • 对30节点进行左单旋。

  • 根据60的平衡因子来更新30和90的平衡因子:当60的平衡因子为0时,30和90的平衡因子也为0;当60的平衡因子为1时,30的平衡因子为-1,90的平衡因子为0;当60的平衡因子为-1时,30的平衡因子为0,90的平衡因子为1。

void RotateRL(Node* parent){Node* subR = parent->right;Node* subRL = subR->left;int bf = subRL->_bf;RotateR(parent->right);RotateL(parent);if (bf == 0){parent->_bf = 0;subR->_bf = 0;subRL->_bf = 0;}else if (bf == 1){parent->_bf = -1;subR->_bf = 0;subRL->_bf = 0;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;subRL->_bf = 0;}else{assert(false);}}

3.判断

我们可以建立一个函数来判断一棵树是否为AVL树。

我们使用递归来进行这一过程,依次判断各个子树是否为AVL树。

要判断我们就需要知道每一棵树的高度,此时我们需要构造一个求树的高度的函数Height。它也由递归来实现。

int Height(Node* root){if (root == nullptr){return 0;}int leftHeight = Height(root->left);int rightHeight = Height(root->right);return rightHeight > leftHeight ? rightHeight + 1 : leftHeight + 1;}bool IsBalance(){return _IsBalance(_root);}bool _IsBalance(Node* root){if (root == nullptr){return true;}int leftHeight = Height(root->left);int rightHeight = Height(root->right);if ((rightHeight - leftHeight) != root->_bf){cout << "现在是:" << root->_bf << endl;cout << "应该是:" << rightHeight - leftHeight << endl;return false;}return abs(rightHeight - leftHeight) < 2 && _IsBalance(root->left) && _IsBalance(root->right);}

4.完整代码及测试代码

完整代码

#pragma once#include<iOStream>#include<assert.h>#include<math.h>using namespace std;struct AVLTreeNode{AVLTreeNode* right;AVLTreeNode* left;AVLTreeNode* parent;pair<int, int> _kv;int _bf;AVLTreeNode(pair<int, int> kv):right(nullptr),left(nullptr),parent(nullptr),_kv(kv),_bf(0){}};class AVLTree{typedef AVLTreeNode Node;public:AVLTree(){_root = nullptr;}void InOrder(){_InOrder(_root);}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->right);}int Height(Node* root){if (root == nullptr){return 0;}int leftHeight = Height(root->left);int rightHeight = Height(root->right);return rightHeight > leftHeight ? rightHeight + 1 : leftHeight + 1;}bool IsBalance(){return _IsBalance(_root);}bool _IsBalance(Node* root){if (root == nullptr){return true;}int leftHeight = Height(root->left);int rightHeight = Height(root->right);if ((rightHeight - leftHeight) != root->_bf){cout << "现在是:" << root->_bf << endl;cout << "应该是:" << rightHeight - leftHeight << endl;return false;}return abs(rightHeight - leftHeight) < 2 && _IsBalance(root->left) && _IsBalance(root->right);}//右单旋void RotateR(Node* parent){Node* cur = parent->left;Node* curL = cur->left;Node* curR = cur->right;Node* parentParent = parent->parent;parent->left = curR;if (curR)curR->parent = parent;cur->right = parent;parent->parent = cur;if (parent == _root){    _root = cur;_root->parent = nullptr;}else{if (parentParent->left == parent){parentParent->left = cur;cur->parent = parentParent;}else if (parentParent->right == parent){parentParent->right = cur;cur->parent = parentParent;}else{assert(false);}}cur->_bf = 0;parent->_bf = 0;}//左单旋void RotateL(Node* parent){Node* cur = parent->right;Node* curL = cur->left;Node* parentParent = parent->parent;parent->right = curL;if (curL)curL->parent = parent;cur->left = parent;parent->parent = cur;if (parent == _root){_root = cur;_root->parent = nullptr;}else{if (parentParent->left == parent){parentParent->left = cur;cur->parent = parentParent;}else if (parentParent->right == parent){parentParent->right = cur;cur->parent = parentParent;}else{assert(false);}}parent->_bf = 0;cur->_bf = 0;}//左右双旋void RotateLR(Node* parent){Node* subL = parent->left;Node* subLR =subL->right;int bf = subLR->_bf;RotateL(parent->left);RotateR(parent);if (bf == 0){parent->_bf = 0;subLR->_bf = 0;subLR->_bf = 0;}else if (bf == -1){parent->_bf = 1;subL->_bf = 0;subLR->_bf = 0;}else if (bf == 1){parent->_bf = 0;subL->_bf = -1;subLR->_bf = 0;}}//右左双旋void RotateRL(Node* parent){Node* subR = parent->right;Node* subRL = subR->left;int bf = subRL->_bf;RotateR(parent->right);RotateL(parent);if (bf == 0){parent->_bf = 0;subR->_bf = 0;subRL->_bf = 0;}else if (bf == 1){parent->_bf = -1;subR->_bf = 0;subRL->_bf = 0;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;subRL->_bf = 0;}else{assert(false);}}bool InsertNode(pair<int, int> kv){//初始化头结点if (_root == nullptr){_root = new Node(kv);return true;}//找到要插入节点的位置Node* cur = _root;Node* parent = nullptr;while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->left;}else{assert(false);}}//插入节点cur = new Node(kv);if (parent->_kv.first<kv.first){parent->right = cur;cur->parent = parent;}else if (parent->_kv.first>kv.first){parent->left = cur;cur->parent = parent;}else{assert(false);}//更新插入节点以上的平衡因子while (parent){if (cur == parent->left){parent->_bf--;}else if (cur == parent->right){parent->_bf++;}if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->parent;}else if (parent->_bf == 2 || parent->_bf == -2){if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);//右单旋}else if (parent->_bf == 2 && cur->_bf == 1){RotateL(parent);//左单旋}else if (parent->_bf == -2 && cur->_bf == 1){RotateLR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){RotateRL(parent);}}else{assert(false);}}}private:Node* _root;};

测试代码

#define _CRT_SECURE_NO_WARNINGS 1  #include"AVLTree.h"void TestRotateR(){AVLTree t;t.InsertNode(make_pair(5, 1));t.InsertNode(make_pair(4, 1));t.InsertNode(make_pair(3, 1));t.InsertNode(make_pair(2, 1));t.InsertNode(make_pair(1, 1));t.InsertNode(make_pair(0, 1));t.InOrder();cout << t.IsBalance() << endl;}void TestRotateL(){AVLTree t;t.InsertNode(make_pair(0, 1));t.InsertNode(make_pair(1, 1));t.InsertNode(make_pair(2, 1));t.InsertNode(make_pair(3, 1));t.InsertNode(make_pair(4, 1));t.InsertNode(make_pair(5, 1));t.InOrder();cout << t.IsBalance() << endl;}void Testbf(){AVLTree t;t.InsertNode(make_pair(5, 1));t.InsertNode(make_pair(7, 1));t.InsertNode(make_pair(3, 1));t.InsertNode(make_pair(4, 1));t.InsertNode(make_pair(2, 1));t.InsertNode(make_pair(8, 1));t.InsertNode(make_pair(9, 1));t.InsertNode(make_pair(6, 1));t.InsertNode(make_pair(1, 1));t.InsertNode(make_pair(11, 1));t.InOrder();cout << t.IsBalance() << endl;}void TestRL(){AVLTree t;t.InsertNode(make_pair(60, 1));t.InsertNode(make_pair(50, 1));t.InsertNode(make_pair(90, 1));t.InsertNode(make_pair(100, 1));t.InsertNode(make_pair(80, 1));t.InsertNode(make_pair(70, 1));t.InOrder();cout << t.IsBalance() << endl;}void TestLR(){AVLTree t;t.InsertNode(make_pair(90, 1));t.InsertNode(make_pair(100, 1));t.InsertNode(make_pair(60, 1));t.InsertNode(make_pair(50, 1));t.InsertNode(make_pair(70, 1));t.InsertNode(make_pair(80, 1));t.InOrder();cout << t.IsBalance() << endl;}int main(){//TestRotateR();//Testbf();//TestRotateL();//TestRL();TestLR();}

感谢各位的阅读,以上就是“C++数据结构之AVL树如何实现”的内容了,经过本文的学习后,相信大家对C++数据结构之AVL树如何实现这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: C++数据结构之AVL树如何实现

本文链接: https://www.lsjlt.com/news/340572.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++数据结构之AVL树如何实现
    这篇文章主要讲解了“C++数据结构之AVL树如何实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++数据结构之AVL树如何实现”吧!1.概念(1)二叉搜索树的缺点要手撕AVL树,我们首先...
    99+
    2023-07-02
  • C++数据结构之AVL树的实现
    目录1.概念(1)二叉搜索树的缺点(2)定义节点2.插入(1)拆分(2)找节点与插节点(3)更新平衡因子与旋转3.判断4.完整代码及测试代码完整代码测试代码1.概念 (1)二叉搜索树...
    99+
    2022-11-13
  • Java数据结构之AVL树实例分析
    这篇文章主要介绍“Java数据结构之AVL树实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java数据结构之AVL树实例分析”文章能帮助大家解决问题。AVL树的引入搜索二叉树有着极高的搜索效...
    99+
    2023-06-30
  • C++数据结构AVL树全面分析
    目录概念AVL树的实现AVL树的节点定义AVL树的插入方法概述平衡因子的调节插入代码实现AVL树的查找AVL树的删除方法概述平衡因子的调节删除代码如下AVL树的测试代码总结⭐️博客代...
    99+
    2022-11-12
  • C++如何实现AVL树
    本篇内容介绍了“C++如何实现AVL树”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!AVL 树的概念也许因为插入的值不够随机,也许因为经过某...
    99+
    2023-07-05
  • AVL树数据结构输入与输出怎么实现
    本篇内容介绍了“AVL树数据结构输入与输出怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!AVL树(平衡二叉树):AVL树本质上是一颗...
    99+
    2023-06-30
  • C++数据结构之红黑树的实现
    目录一、什么是红黑树二、红黑树的约定三、红黑树vsAVL四、红黑树的实现1.找到插入的位置2.控制平衡3.测试代码五、完整代码1.test.c2.RBTree.h一、什么是红黑树 红...
    99+
    2022-11-13
    C++ 数据结构 红黑树 C++ 红黑树
  • C++数据结构之搜索二叉树的实现
    目录零.前言1.概念2.作用3.迭代实现(1)查找(2)插入(3)删除4.递归实现(1)查找(2)插入(3)删除5.key/value模型的应用(1)对应查找(2)判断出现次数6.总...
    99+
    2022-11-13
  • 用Python实现数据结构之树
    树是由根结点和若干颗子树构成的。树是由一个集合以及在该集合上定义的一种关系构成的。集合中的元素称为树的结点,所定义的关系称为父子关系。父子关系在树的结点之间建立了一个层次结构。在这种层次结构中有一个结点具有特殊的地位,这个结点称为该树...
    99+
    2023-01-30
    数据结构 之树 Python
  • 图解AVL树数据结构输入与输出及实现示例
    目录AVL树(平衡二叉树):AVL树的作用:AVL树的基本操作:AVL树的插入,单旋转的第一种情况---右旋:AVL树的插入,单旋转的第二种情况---左旋:AVL树的插入,双旋转的第...
    99+
    2022-11-13
  • C++高级数据结构之线段树
    目录前言:高级数据结构(Ⅲ)线段树(Segment Tree)线段树的原理树的创建单点修改区间查找完整代码及测试前言: 高级数据结构(Ⅲ)线段树(Segment Tree)线段树的原...
    99+
    2022-11-13
  • C++数据结构之二叉搜索树的实现详解
    目录前言介绍实现节点的实现二叉搜索树的查找二叉搜索树的插入二叉搜索树的删除总结前言 今天我们来学一个新的数据结构:二叉搜索树。 介绍 二叉搜索树也称作二叉排序树,它具有以下性质: 非...
    99+
    2022-11-13
  • C++高级数据结构之二叉查找树怎么实现
    本文小编为大家详细介绍“C++高级数据结构之二叉查找树怎么实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“C++高级数据结构之二叉查找树怎么实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。高级数据结构(Ⅳ)...
    99+
    2023-06-30
  • C语言数据结构之二叉树详解
    目录1. 树概念及结构1.1树概念1.2树的表示2. 二叉树概念及结构2.1概念2.2数据结构中的二叉树2.3特殊的二叉树2.4二叉树的存储结构2.5二叉树的性质3. 二叉树顺序结构...
    99+
    2022-11-13
  • C++高级数据结构之二叉查找树
    目录高级数据结构(Ⅳ)二叉查找树基础概念基本实现数据表示查找插入有序性相关的方法最小键和最大键向上取整和向下取整选择操作排名范围查找与删除相关的方法删除最小键删除最大键删除操作性能分...
    99+
    2022-11-13
  • C++数据结构之哈希表如何实现
    本篇内容主要讲解“C++数据结构之哈希表如何实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C++数据结构之哈希表如何实现”吧!哈希表概念二叉搜索树具有对数时间的表现,但这样的表现建立在一个假...
    99+
    2023-07-05
  • C++数据结构之单链表如何实现
    这篇文章主要介绍了C++数据结构之单链表如何实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++数据结构之单链表如何实现文章都会有所收获,下面我们一起来看看吧。一、单链表的定义线性表的链式存储又称为单链表,...
    99+
    2023-06-30
  • Java数据结构之二叉排序树的实现
    目录1 二叉排序树的概述2 二叉排序树的构建2.1 类架构2.2 查找的方法2.3 插入的方法2.4 查找最大值和最小值2.5 删除的方法3 二叉排序树的总结1 二叉排序树的概述 本...
    99+
    2022-11-13
  • Java数据结构之二叉查找树的实现
    目录定义节点结构查找算法插入算法删除算法完整代码定义 二叉查找树(亦称二叉搜索树、二叉排序树)是一棵二叉树,且各结点关键词互异,其中根序列按其关键词递增排列。 等价描述:二叉查找树中...
    99+
    2022-11-13
  • Java数据结构之哈夫曼树概述及实现
    目录一、与哈夫曼树相关的概念二、什么是哈夫曼树三、哈夫曼树的构造方法四、哈夫曼树的代码实现一、与哈夫曼树相关的概念 概念 ...
    99+
    2022-11-12
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作