我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C语言平衡二叉树的示例分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C语言平衡二叉树的示例分析

这篇文章给大家分享的是有关C语言平衡二叉树的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。

    平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。这个方案很好的解决了二叉查找树退化成链表的问题,把插入,查找,删除的时间复杂度最好情况和最坏情况都维持在O(logN)。但是频繁旋转会使插入和删除牺牲掉O(logN)左右的时间,不过相对二叉查找树来说,时间上稳定了很多。

    C语言平衡二叉树的示例分析

    平衡二叉树大部分操作和二叉查找树类似,主要不同在于插入删除的时候平衡二叉树的平衡可能被改变,并且只有从那些插入点到根结点的路径上的结点的平衡性可能被改变,因为只有这些结点的子树可能变化。

    平衡二叉树不平衡的情形:

    把需要重新平衡的结点叫做α,由于任意两个结点最多只有两个儿子,因此高度不平衡时,α结点的两颗子树的高度相差2.容易看出,这种不平衡可能出现在下面4中情况中:

    对α的左儿子的左子树进行一次插入

    对α的左儿子的右子树进行一次插入

    对α的右儿子的左子树进行一次插入

    对α的右儿子的右子树进行一次插入

    C语言平衡二叉树的示例分析

    情形1和情形4是关于α的镜像对称,二情形2和情形3也是关于α的镜像对称,因此理论上看只有两种情况,但编程的角度看还是四种情形。

    第一种情况是插入发生在“外边”的情形(左左或右右),该情况可以通过一次单旋转完成调整;第二种情况是插入发生在“内部”的情形(左右或右左),这种情况比较复杂,需要通过双旋转来调整。

    调整措施:

    一、单旋转

    C语言平衡二叉树的示例分析

    上图是左左的情况,k2结点不满足平衡性,它的左子树k1比右子树z深两层,k1子树中更深的是k1的左子树x,因此属于左左情况。

    为了恢复平衡,我们把x上移一层,并把z下移一层,但此时实际已经超出了AVL树的性质要求。为此,重新安排结点以形成一颗等价的树。为使树恢复平衡,我们把k2变成这棵树的根节点,因为k2大于k1,把k2置于k1的右子树上,而原本在k1右子树的Y大于k1,小于k2,就把Y置于k2的左子树上,这样既满足了二叉查找树的性质,又满足了平衡二叉树的性质。

    这种情况称为单旋转。

    二、双旋转

    对于左右和右左两种情况,单旋转不能解决问题,要经过两次旋转。

    C语言平衡二叉树的示例分析

    对于上图情况,为使树恢复平衡,我们需要进行两步,第一步,把k1作为根,进行一次右右旋转,旋转之后就变成了左左情况,所以第二步再进行一次左左旋转,最后得到了一棵以k2为根的平衡二叉树。

    AVL树的删除操作:

    同插入操作一样,删除结点时也有可能破坏平衡性,这就要求我们删除的时候要进行平衡性调整。

    删除分为以下几种情况:

    首先在整个二叉树中搜索要删除的结点,如果没搜索到直接返回不作处理,否则执行以下操作:

    1.要删除的节点是当前根节点T。

    如果左右子树都非空。在高度较大的子树中实施删除操作。

    分两种情况:

    (1)、左子树高度大于右子树高度,将左子树中最大的那个元素赋给当前根节点,然后删除左子树中元素值最大的那个节点。

    (1)、左子树高度小于右子树高度,将右子树中最小的那个元素赋给当前根节点,然后删除右子树中元素值最小的那个节点。

    如果左右子树中有一个为空,那么直接用那个非空子树或者是NULL替换当前根节点即可。

    2、要删除的节点元素值小于当前根节点T值,在左子树中进行删除。

    递归调用,在左子树中实施删除。

    这个是需要判断当前根节点是否仍然满足平衡条件,

    如果满足平衡条件,只需要更新当前根节点T的高度信息。

    否则,需要进行旋转调整:

    如果T的左子节点的左子树的高度大于T的左子节点的右子树的高度,进行相应的单旋转。否则进行双旋转。

    3、要删除的节点元素值大于当前根节点T值,在右子树中进行删除。

    下面给出详细代码实现:

    AvlTree.h

    #include <iostream>#include <algorithm>using namespace std;#pragma once//平衡二叉树结点template <typename T>struct AvlNode{    T data;    int height; //结点所在高度    AvlNode<T> *left;    AvlNode<T> *right;    AvlNode<T>(const T theData) : data(theData), left(NULL), right(NULL), height(0){}};//AvlTreetemplate <typename T>class AvlTree{public:    AvlTree<T>(){}    ~AvlTree<T>(){}    AvlNode<T> *root;    //插入结点    void Insert(AvlNode<T> *&t, T x);    //删除结点    bool Delete(AvlNode<T> *&t, T x);    //查找是否存在给定值的结点    bool Contains(AvlNode<T> *t, const T x) const;    //中序遍历    void InorderTraversal(AvlNode<T> *t);    //前序遍历    void PreorderTraversal(AvlNode<T> *t);    //最小值结点    AvlNode<T> *FindMin(AvlNode<T> *t) const;    //最大值结点    AvlNode<T> *FindMax(AvlNode<T> *t) const;private:    //求树的高度    int GetHeight(AvlNode<T> *t);    //单旋转 左    AvlNode<T> *LL(AvlNode<T> *t);    //单旋转 右    AvlNode<T> *RR(AvlNode<T> *t);    //双旋转 右左    AvlNode<T> *LR(AvlNode<T> *t);    //双旋转 左右    AvlNode<T> *RL(AvlNode<T> *t);};template <typename T>AvlNode<T> * AvlTree<T>::FindMax(AvlNode<T> *t) const{    if (t == NULL)        return NULL;    if (t->right == NULL)        return t;    return FindMax(t->right);}template <typename T>AvlNode<T> * AvlTree<T>::FindMin(AvlNode<T> *t) const{    if (t == NULL)        return NULL;    if (t->left == NULL)        return t;    return FindMin(t->left);}template <typename T>int AvlTree<T>::GetHeight(AvlNode<T> *t){    if (t == NULL)        return -1;    else        return t->height;}//单旋转//左左插入导致的不平衡template <typename T>AvlNode<T> * AvlTree<T>::LL(AvlNode<T> *t){    AvlNode<T> *q = t->left;    t->left = q->right;    q->right = t;    t = q;    t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;    q->height = max(GetHeight(q->left), GetHeight(q->right)) + 1;    return q;}//单旋转//右右插入导致的不平衡template <typename T>AvlNode<T> * AvlTree<T>::RR(AvlNode<T> *t){    AvlNode<T> *q = t->right;    t->right = q->left;    q->left = t;    t = q;    t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;    q->height = max(GetHeight(q->left), GetHeight(q->right)) + 1;    return q;}//双旋转//插入点位于t的左儿子的右子树template <typename T>AvlNode<T> * AvlTree<T>::LR(AvlNode<T> *t){    //双旋转可以通过两次单旋转实现    //对t的左结点进行RR旋转,再对根节点进行LL旋转    RR(t->left);    return LL(t);}//双旋转//插入点位于t的右儿子的左子树template <typename T>AvlNode<T> * AvlTree<T>::RL(AvlNode<T> *t){    LL(t->right);    return RR(t);}template <typename T>void AvlTree<T>::Insert(AvlNode<T> *&t, T x){    if (t == NULL)        t = new AvlNode<T>(x);    else if (x < t->data)    {        Insert(t->left, x);        //判断平衡情况        if (GetHeight(t->left) - GetHeight(t->right) > 1)        {            //分两种情况 左左或左右            if (x < t->left->data)//左左                t = LL(t);            else                  //左右                t = LR(t);        }    }    else if (x > t->data)    {        Insert(t->right, x);        if (GetHeight(t->right) - GetHeight(t->left) > 1)        {            if (x > t->right->data)                t = RR(t);            else                t = RL(t);        }    }    else        ;//数据重复    t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;}template <typename T>bool AvlTree<T>::Delete(AvlNode<T> *&t, T x){    //t为空 未找到要删除的结点    if (t == NULL)        return false;    //找到了要删除的结点    else if (t->data == x)    {        //左右子树都非空        if (t->left != NULL && t->right != NULL)        {//在高度更大的那个子树上进行删除操作            //左子树高度大,删除左子树中值最大的结点,将其赋给根结点            if (GetHeight(t->left) > GetHeight(t->right))            {                t->data = FindMax(t->left)->data;                Delete(t->left, t->data);            }            else//右子树高度更大,删除右子树中值最小的结点,将其赋给根结点            {                t->data = FindMin(t->right)->data;                Delete(t->right, t->data);            }        }        else        {//左右子树有一个不为空,直接用需要删除的结点的子结点替换即可            AvlNode<T> *old = t;            t = t->left ? t->left: t->right;//t赋值为不空的子结点            delete old;        }    }    else if (x < t->data)//要删除的结点在左子树上    {        //递归删除左子树上的结点        Delete(t->left, x);        //判断是否仍然满足平衡条件        if (GetHeight(t->right) - GetHeight(t->left) > 1)        {            if (GetHeight(t->right->left) > GetHeight(t->right->right))            {                //RL双旋转                t = RL(t);            }            else            {//RR单旋转                t = RR(t);            }        }        else//满足平衡条件 调整高度信息        {            t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;        }    }    else//要删除的结点在右子树上    {        //递归删除右子树结点        Delete(t->right, x);        //判断平衡情况        if (GetHeight(t->left) - GetHeight(t->right) > 1)        {            if (GetHeight(t->left->right) > GetHeight(t->left->left))            {                //LR双旋转                t = LR(t);            }            else            {                //LL单旋转                t = LL(t);            }        }        else//满足平衡性 调整高度        {            t->height = max(GetHeight(t->left), GetHeight(t->right)) + 1;        }    }    return true;}//查找结点template <typename T>bool AvlTree<T>::Contains(AvlNode<T> *t, const T x) const{    if (t == NULL)        return false;    if (x < t->data)        return Contains(t->left, x);    else if (x > t->data)        return Contains(t->right, x);    else        return true;}//中序遍历template <typename T>void AvlTree<T>::InorderTraversal(AvlNode<T> *t){    if (t)    {        InorderTraversal(t->left);        cout << t->data << ' ';        InorderTraversal(t->right);    }}//前序遍历template <typename T>void AvlTree<T>::PreorderTraversal(AvlNode<T> *t){    if (t)    {        cout << t->data << ' ';        PreorderTraversal(t->left);        PreorderTraversal(t->right);    }}

    main.cpp

    #include "AvlTree.h"int main(){    AvlTree<int> tree;    int value;    int tmp;    cout << "请输入整数建立二叉树(-1结束):" << endl;    while (cin >> value)    {        if (value == -1)            break;        tree.Insert(tree.root,value);    }    cout << "中序遍历";    tree.InorderTraversal(tree.root);    cout << "\n前序遍历:";    tree.PreorderTraversal(tree.root);    cout << "\n请输入要查找的结点:";    cin >> tmp;    if (tree.Contains(tree.root, tmp))        cout << "已查找到" << endl;    else        cout << "值为" << tmp << "的结点不存在" << endl;    cout << "请输入要删除的结点:";    cin >> tmp;    tree.Delete(tree.root, tmp);    cout << "删除后的中序遍历:";    tree.InorderTraversal(tree.root);    cout << "\n删除后的前序遍历:";    tree.PreorderTraversal(tree.root);}

    测试结果

    C语言平衡二叉树的示例分析

    感谢各位的阅读!关于“C语言平衡二叉树的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!

    免责声明:

    ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

    ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

    C语言平衡二叉树的示例分析

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

    下载Word文档

    猜你喜欢

    C语言平衡二叉树的示例分析

    这篇文章给大家分享的是有关C语言平衡二叉树的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。平衡二叉树(Balanced Binary Tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一
    2023-06-25

    C语言中二叉树的示例分析

    这篇文章主要为大家展示了“C语言中二叉树的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“C语言中二叉树的示例分析”这篇文章吧。树概念及结构树是一种 非线性 的数据结构,它是由 n ( n
    2023-06-29

    Java平衡二叉树实例分析

    这篇文章主要讲解了“Java平衡二叉树实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Java平衡二叉树实例分析”吧!AVL树的引入搜索二叉树有着极高的搜索效率,但是搜索二叉树会出现以
    2023-06-30

    C语言之平衡二叉树详解

    平衡二叉树是具有平衡属性的有序二叉树,本文主要介绍了C语言中的平衡二叉树,具有一定的参考价值,需要的小伙伴可以参考阅读
    2023-05-17

    C语言平衡二叉树问题怎么解决

    这篇文章主要介绍“C语言平衡二叉树问题怎么解决”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C语言平衡二叉树问题怎么解决”文章能帮助大家解决问题。一、题目描述给定一个二叉树,判断它是否是高度平衡的二
    2023-06-30

    C++AVLTree高度平衡的二叉搜索树深入分析

    这篇文章主要介绍了C++AVLTree高度平衡的二叉搜索树,二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下
    2023-03-08

    C++树与二叉树实例分析

    这篇“C++树与二叉树实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C++树与二叉树实例分析”文章吧。树树的定义Q:
    2023-06-30

    Java中二叉树与N叉树的示例分析

    这篇文章主要介绍了Java中二叉树与N叉树的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。题目一 解法/** * Definition for a binary tr
    2023-06-29

    镜像二叉树的示例分析

    镜像二叉树的示例分析,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。算法这个东西很难,纵使你了解了其中的逻辑,用代码写出来仍然不是一件容易的事,内部有太多的细节需
    2023-06-04

    C++二叉搜索树实例分析

    本篇内容介绍了“C++二叉搜索树实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!独一无二的二叉搜索树Given an integer
    2023-06-19

    java二叉树面试题的示例分析

    小编给大家分享一下java二叉树面试题的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!二叉树的深度题目:输入一颗二叉树的根节点,求该树的的深度。输入一颗二
    2023-06-20

    编程热搜

    • Python 学习之路 - Python
      一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
      Python 学习之路 - Python
    • chatgpt的中文全称是什么
      chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
      chatgpt的中文全称是什么
    • C/C++中extern函数使用详解
    • C/C++可变参数的使用
      可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
      C/C++可变参数的使用
    • css样式文件该放在哪里
    • php中数组下标必须是连续的吗
    • Python 3 教程
      Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
      Python 3 教程
    • Python pip包管理
      一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
      Python pip包管理
    • ubuntu如何重新编译内核
    • 改善Java代码之慎用java动态编译

    目录