本例子分为3个文件。

类声明头文件  hAVL.h
#ifndef AVLTREE_H_INCLUDED
#define AVLTREE_H_INCLUDED//AVL树数据结构定义
typedef int ElementType;//AVL数节点包含数据类型//树节点
typedef struct AVLNode{ElementType element;//节点包含的数据元素AVLNode *left;//节点左子树AVLNode *right;//节点右子树int height;//节点所在的高度
}*AVLTree;//AVL tree类封装
class CAVLTree{
private://供内部调用的函数int getHeight(AVLTree);//求得树的高度void setHeight(AVLTree, int);//设置节点的高度值//单旋转:向右旋转
    AVLTree SingleRightRotate(AVLTree);//单旋转:向左旋转
    AVLTree SingleLeftRotate(AVLTree);//双旋转:左右
    AVLTree DoubleRightRotate(AVLTree);//双旋转:右左
    AVLTree DoubleLeftRotate(AVLTree);public://默认构造函数
    CAVLTree();//析构函数~CAVLTree();//创建AVL树void createAVLTree(ElementType *data, int n);//插入节点
    AVLTree insertNode(AVLTree T, ElementType val);//删除树中元素值等于某值的节点AVLTree deleteNode(AVLTree T, const ElementType val);//搜寻元素值等于某值的节点
    AVLTree searchNode(AVLTree, ElementType);//前序遍历输出树void preOrder(AVLTree T);//得到树中的元素值最大的节点
    AVLTree getMaxNode(AVLTree);//得到树中的元素值最小的那个节点
    AVLTree getMinNode(AVLTree);void deleteTree(AVLTree t);AVLTree T;
};#endif // AVLTREE_H_INCLUDED

//右右外侧插入导致的不平衡,采用单旋转-左旋转进行修正
//参数解释:类实现文件AVLTr.cpp

#include "stdafx.h"
#include "hAVL.h"#include <iostream>
#include <cmath>
#include <math.h>
#include <cassert>using namespace std;int  fmax(int i, int j)
{return i>j?i:j;
};CAVLTree::CAVLTree()
{T = NULL;
}CAVLTree::~CAVLTree()
{deleteTree(T);
}//依据各元素的数据值,创建AVL树
void CAVLTree::createAVLTree(ElementType *data, int n)
{if (T){cout << "The AVL Tree has been created" << endl;return;}if (!n)//元素序列为空
    {T = NULL;return;}for (int i = 0; i < n; ++i){T = insertNode(T, *(data + i));}return;
}AVLTree CAVLTree::insertNode(AVLTree T, ElementType val)
{AVLNode *pNewNode = new AVLNode;pNewNode->element = val;pNewNode->left = NULL;pNewNode->right = NULL;pNewNode->height = 1;//新节点一定被插入在空节点的位置if (NULL == T){T = pNewNode;return T;}//需要插入节点的树非空//插入的元素已经存在于树中,不符合要求if (val == T->element){cout << "元素中有重复,构建AVL树失败!" << endl;return T;}//要插入的值小于根节点的值,将其插入左子树中if (val < T->element){//将其插入根节点的左子树中T->left = insertNode(T->left, val);//判断平衡条件是否仍然满足if (getHeight(T->left) - getHeight(T->right) > 1){//分两种情况进行旋转操作//插入点位于T的左子结点的左子树if (val < T->left->element)//实施单旋转-右旋转T = SingleRightRotate(T);else//插入点位于T的左子结点的右子树,实施双右旋转T = DoubleRightRotate(T);}}//要插入的值大于根节点的值,将其插入右子树中if (val > T->element){T->right = insertNode(T->right, val);//判断平衡条件是否仍然满足if (getHeight(T->right) - getHeight(T->left) > 1){//节点插入到T的右子节点的右子树中if (val > T->right->element)//实施单旋转-左旋转T = SingleLeftRotate(T);else//节点插入到T的右子节点的左子树上//实施双旋转-左旋转T = DoubleLeftRotate(T);}}//更新节点的height值setHeight(T, fmax(getHeight(T->left), getHeight(T->right)) + 1);return T;
}AVLTree CAVLTree::deleteNode(AVLTree T, const ElementType val)
{if (!T){cout << "The tree is NULL, delete failed" << endl;return T;}AVLTree searchedNode = searchNode(T, val);//没有找到相应的节点,删除失败if (!searchedNode){cout << "Cann't find the node to delete " << val << endl;return T;}//找到了需要删除的节点//需要删除的节点就是当前子树的根节点if (val == T->element){//左右子树都非空if (T->left && T->right){//在高度更大的那个子树上进行删除操作if (getHeight(T->left) > getHeight(T->right)){//左子树高度大,删除左子树中元素值最大的那个节点,同时将其值赋值给根节点T->element = getMaxNode(T->left)->element;T->left = deleteNode(T->left, T->element);}else{//删除右子树中元素值最小的那个节点,同时将其值赋值给根节点T->element = getMinNode(T->right)->element;T->right = deleteNode(T->right, T->element);}}else{//左右子树中有一个不为空,那个直接用需要被删除的节点的子节点替换之即可AVLTree oldNode = T;T = (T->left ? T->left : T->right);delete oldNode;//释放节点所占的空间oldNode = NULL;}}else if (val < T->element)//要删除的节点在左子树中
    {//在左子树中进行递归删除T->left = deleteNode(T->left, val);//判断是否仍然满足平衡条件if (getHeight(T->right) - getHeight(T->left) > 1){if (T->right->left > T->right->right){//左双旋转T = DoubleLeftRotate(T);}else//进行左单旋转T = SingleLeftRotate(T);}else//满足平衡条件,需要更新高度信息T->height = fmax(getHeight(T->left), getHeight(T->right)) + 1;}else//需要删除的节点在右子树中
    {T->right = deleteNode(T->right, val);//判断是否满足平衡条件if (getHeight(T->left) - getHeight(T->right) > 1){if (getHeight(T->left->right) > getHeight(T->left->left))//右双旋转T = DoubleRightRotate(T);else//右单旋转T = SingleRightRotate(T);}else//只需调整高度即可T->height = fmax(getHeight(T->left), getHeight(T->right)) + 1;}return T;
}AVLTree CAVLTree::searchNode(AVLTree T, ElementType val)
{if (!T){return NULL;}//搜索到if (val == T->element){return T;}else if (val < T->element){//在左子树中搜索return searchNode(T->left, val);}else{//在右子树中搜索return searchNode(T->right, val);}
}void CAVLTree::preOrder(AVLTree T)
{if (!T)cout << "NULL ";else{cout << T->element << " ";preOrder(T->left);preOrder(T->right);}
}AVLTree CAVLTree::getMaxNode(AVLTree T)
{if (!T)//树为空
    {return NULL;}AVLTree tempNode = T;//向右搜寻直至右子节点为NULLwhile (tempNode->right){tempNode = tempNode->right;}return tempNode;
}AVLTree CAVLTree::getMinNode(AVLTree T)
{if (!T)//树为空
    {return NULL;}AVLTree tempNode = T;//向左搜寻直至左子结点为NULLwhile (tempNode->left){tempNode = tempNode->left;}return tempNode;
}int CAVLTree::getHeight(AVLTree T)
{return (T == NULL) ? 0 : (T->height);
}void CAVLTree::setHeight(AVLTree T, int height)
{T->height = height;
}//左左外侧插入导致的不平衡,采用单旋转-右旋转进行修正
//参数解释:
//T:指向因某种操作失去平衡的最小子树根节点
AVLTree CAVLTree::SingleRightRotate(AVLTree T)
{AVLTree xPNode = T;AVLTree yPNode = T->left;xPNode->left = yPNode->right;//更改原根节点的左子树yPNode->right = xPNode;//更改原根节点左孩子的右子树//更新进行了旋转操作的节点的高度xPNode->height = fmax(getHeight(xPNode->left), getHeight(xPNode->right)) + 1;yPNode->height = fmax(getHeight(yPNode->left), getHeight(yPNode->right)) + 1;//原根节点的左孩子节点成为新的根节点return yPNode;//T:指向因某种操作失去平衡的最小子树根节点
AVLTree CAVLTree::SingleLeftRotate(AVLTree T)
{AVLTree xPNode = T;AVLTree yPNode = T->right;xPNode->right = yPNode->left;//更改原根节点的右孩子yPNode->left = xPNode;//提升原根节点的右孩子节点为新的根节点//更新执行了旋转操作的节点的高度信息xPNode->height = fmax(getHeight(xPNode->left), getHeight(xPNode->right)) + 1;yPNode->height = fmax(getHeight(yPNode->left), getHeight(yPNode->right)) + 1;//返回新的根节点return yPNode;
}//插入点位于T的左子结点的右子树
AVLTree CAVLTree::DoubleRightRotate(AVLTree T)
{//双旋转可以通过两次单旋转实现//第一次单旋转assert(T->left != NULL);//对其左子树进行一次单旋转-左旋转T->left = SingleLeftRotate(T->left);//第二次单旋转//对新产生的树进行一次单旋转-右旋转return SingleRightRotate(T);
}//插入点位于T的右子节点的左子树
AVLTree CAVLTree::DoubleLeftRotate(AVLTree T)
{//双旋转可以通过两次单旋转实现//第一次单旋转assert(T->right != NULL);//对其右子树进行一次单旋转-右旋转T->right = SingleRightRotate(T->right);//第二次单旋转//对新产生的树进行一次单旋转-左旋转return SingleLeftRotate(T);
}void CAVLTree::deleteTree(AVLTree t)
{if (NULL == t)return;deleteTree(t->left);deleteTree(t->right);delete t;t = NULL;
}

主函数文件 main.cpp
// AVLTree.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"//平衡二叉树搜索树(AVL tree-Adelson-Velskii-Landis tree)编程实现
#include "hAVL.h"
#include <iostream>
using namespace std;int main()
{// 通过给定序列创建平衡二叉树const int NumElements = 8;cout << "AVL树各项操作编程实现:" << endl;int a[NumElements] = { 25,2,64,45,12,34,9,18};CAVLTree *CAVLTreeObj1 = new CAVLTree();CAVLTreeObj1->createAVLTree(a, NumElements);cout << "AVL Tree先序遍历结果:" << endl;CAVLTreeObj1->preOrder(CAVLTreeObj1->T);cout << endl;// 插入一个新的数据int insertedVal1 = 15;CAVLTreeObj1->T = CAVLTreeObj1->insertNode(CAVLTreeObj1->T, insertedVal1);cout << "向AVL树中插入元素  " << insertedVal1 << "之后的先序遍历结果:" << endl;CAVLTreeObj1->preOrder(CAVLTreeObj1->T);cout << endl << endl;// 在插入一个新的数据(由重复数据情况下)int insertedVal2 = 16;CAVLTreeObj1->T = CAVLTreeObj1->insertNode(CAVLTreeObj1->T, insertedVal2);cout << "向AVL树中插入元素  " << insertedVal2 << "之后的先序遍历结果:" << endl;CAVLTreeObj1->preOrder(CAVLTreeObj1->T);cout << endl << endl;// 寻找最小的元素int minVal = CAVLTreeObj1->getMinNode(CAVLTreeObj1->T)->element;cout << "树中最小的元素是:" << minVal << endl;cout << endl;// 寻找最大的元素int maxVal = CAVLTreeObj1->getMaxNode(CAVLTreeObj1->T)->element;cout << "树中最大的元素是:" << maxVal << endl;cout << endl;// 删除1个元素const int deletedVal1 = 11;CAVLTreeObj1->T = CAVLTreeObj1->deleteNode(CAVLTreeObj1->T, deletedVal1);cout << "删除元素值为 " << deletedVal1 << "的节点之后的树先序遍历结果:" << endl;CAVLTreeObj1->preOrder(CAVLTreeObj1->T);    cout << endl << endl;// 删除第2个元素const int deletedVal2 = 20;CAVLTreeObj1->T = CAVLTreeObj1->deleteNode(CAVLTreeObj1->T, deletedVal2);cout << "删除元素值为 " << deletedVal2 << "的节点之后的树先序遍历结果:" << endl;CAVLTreeObj1->preOrder(CAVLTreeObj1->T);cout << endl << endl;// 删除第3个元素const int deletedVal3 = 18;CAVLTreeObj1->T = CAVLTreeObj1->deleteNode(CAVLTreeObj1->T, deletedVal3);cout << "删除元素值为 " << deletedVal3 << "的节点之后的树先序遍历结果:" << endl;CAVLTreeObj1->preOrder(CAVLTreeObj1->T);cout << endl << endl;const int searchedVal1 = 12;AVLTree searchedPNode = CAVLTreeObj1->searchNode(CAVLTreeObj1->T, searchedVal1);if (!searchedPNode)cout << "cannot find such node whose elemen equals " << searchedVal1 << endl;elsecout << "search success element " << searchedVal1 << endl;const int searchedVal2 = 13;searchedPNode = CAVLTreeObj1->searchNode(CAVLTreeObj1->T, searchedVal2);if (!searchedPNode)cout << "cannot find such node whose elemen equals " << searchedVal2 << endl;elsecout << "search success element " << searchedVal2 << endl;cout << endl << endl;getchar();return 0;
}

转载于:https://www.cnblogs.com/gd-luojialin/p/8509131.html

16-1平衡树源代码相关推荐

  1. PostgreSQL 10.1 手册_部分 III. 服务器管理_第 16 章 从源代码安装_16.5. 安装后设置...

    16.5. 安装后设置 16.5.1. 共享库16.5.2. 环境变量 16.5.1. 共享库 在一些有共享库的系统里,你需要告诉你的系统如何找到新安装的共享库.那些并不是必须做这个工作的系统包括 F ...

  2. python爬取电影票房前50_Python3爬取起猫眼电影实时票房信息,解决文字反爬~~~附源代码...

    上文解决了起点中文网部分数字反爬的信息,详细链接https://www.cnblogs.com/aby321/p/10214123.html 本文研究另一种文字反爬的机制--猫眼电影实时票房反爬 虽然 ...

  3. 利用10位AD转换器 及 LED 数码管,实现由AD转换器采集温度,并用数码管显示。温度超出一定范围,LED 指示灯闪烁报警。(主要分析进制16进制转换10进制,并用数码管显示问题)

    ** 题目: ** 利用原有的电路 AD 及 LED 数码管显示等例子,进行整合.实现由 AD转换器采集温度(用可调电阻模拟),温度在数码管上显示.当温度超出一定范围,用 LED 指示灯进行闪烁报警. ...

  4. (转)C语言位运算详解

    地址:http://www.cnblogs.com/911/archive/2008/05/20/1203477.html C语言位运算详解 作者:911 说明:本文参考了http://www2.ts ...

  5. gluPerspective和gluLookAt的关系

    参考文章 GL学习笔记(2) - 终于搞明白gluPerspective和gluLookAt的关系了(zz) gluPerspective的具体含义 解密--神秘的gluPerspective 函数原 ...

  6. login窗口for mysql_CTF| SQL注入之login界面

    SQL注入是CTF的WEB方向必不可少的一种题型,斗哥最近也做了一些在线题目,其中最常见的题目就是给出一个登录界面,让我们绕过限制登录或者一步步注入数据. 万能密码-very easy 题目入口:ht ...

  7. JAVA16版本.JDK16即将发布,你准备好了吗?

    岁月无声,岁月有声.2020实鼠不易,2021牛转乾坤. 当我们开发者与大多企业还停留在JDK8的时候,JDK16即将问世,你准备好了吗? 郑重申明: 第一次冒险翻译专业领域的文献,可想而知,效果特别 ...

  8. 在 .NET 中加载椭圆曲线 (EC) 密钥

    在 .NET 中加载椭圆曲线 (EC) 密钥 本文将讨论在.NET 中解析和加载EC 密钥的不同方式.在本文中,您将了解 EC 密钥的构成,然后了解如何以四种不同的方式使用这些知识ECDsa在 .NE ...

  9. C的|、||、、、异或、~

    位运算     位运算的运算分量只能是整型或字符型数据,位运算把运算对象看作是由二进位组成的位串信息,按位完成指定的运算,得到位串信息的结果. 位运算符有: &(按位与).|(按位或).^(按 ...

最新文章

  1. 修改密码后服务器断开连接,SSH无需密码登录服务器且保持连接不断开的方法
  2. 从EEG中解码想象的3D手臂运动轨迹以控制两个虚拟手臂
  3. python和c学习-python与c++交互学习入门之5
  4. Hadoop安装记录(伪分布式)
  5. C#使用post提交http请求
  6. Educational Codeforces Round 40 (Rated for Div. 2)
  7. 领域驱动设计在马蜂窝优惠中心重构中的实践
  8. 使用Boxfuse轻松在云中运行Spring Boot应用程序
  9. 使用Dundas控件在web应用上展现多维数据集(二)
  10. VMWare学习总结(3)——Vmware Workstation 14虚拟机网卡桥接连不上网络解决方法
  11. IAR中如何实时观察变量值
  12. numpy教程:统计函数Statistics
  13. Xcode中AutoLayOut的简单使用
  14. 视觉SLAM十四讲学习笔记——ch9后端1
  15. 1024程序员节节日快乐
  16. 逻辑谬误_新网络谬误
  17. 防拷贝加密U盘的功能有些
  18. 烟台大学计算机学院王文学,杨玉军-烟台大学 数学与信息科学学院
  19. android自定义Dcloud插件,调用android原生界面并获取返回数据
  20. 企业如何防止激光打印机泄密?

热门文章

  1. js计算数组中每个元素出现的次数(2种方法)
  2. [资源]181个Python开源项目分享!
  3. P2896 [USACO08FEB]一起吃饭Eating Together 解题报告
  4. 关于tag,viewWithTag
  5. 马丁 福勒 Martin Fowler 关于依赖注入和反转控制的区别
  6. MVC中使用ajax传递json数组
  7. C#下如何实现服务器 + 客户端的聊天程序
  8. Javascript玩转Prototype(一)——先谈C#原型模式
  9. Windows 系统补丁管理策略
  10. linux备份mysql部分表数据,linux mysql 数据按表名称备份