AVL树

【0】README

0.1)本文给出了平衡二叉树(AVL树)的插入例程涉及到的单旋转+双旋转的概念,并给出了代码实现;
0.2)本文源代码均为原创, 当然相关idea 还是借鉴人家的;(真心有点难,这个实现起来)
0.3) for detailed single rotate and double rotates , please visit http://blog.csdn.net/PacosonSWJTU/article/details/50522677


【1】AVL树

1.1)定义: AVL树是根据它的发明者G. M. Adelson-Velskii和E. M. Landis命名的。它是一种特殊的二叉查找树;
1.2)AVL树要求: 任一节点的左子树深度和右子树深度相差不超过1(空树高度定义为-1);
1.3)最简单的想法:要求左右子树具有相同的高度,这种想法并不强求树的深度要浅;
1.4)我们把必须重新平衡的节点叫做 α, 由于任意节点最多有两个儿子, 因此高度不平衡时, α 点的两颗子树的高度差2;


【2】AVL树的不平衡情况分析

2.1)AVL树的不平衡可能出现在下面四种情况:

  • 1) 对α 的左儿子的左子树进行一次插入(左-左);
  • 2) 对α 的左儿子的右子树进行一次插入(左-右);
  • 3) 对α 的右儿子的左子树进行一次插入(右-左);
  • 4) 对α 的右儿子的右子树进行一次插入(右-右);

2.2)对以上情况的Analysis:

  • A1)上述情况中的 第1种 和 第4种情况 是插入发生在外部的情况(即左-左 or 右-右情况), 这种情况通过单旋转来处理;
  • A2)上述情况中的 第2种 和 第3种情况 是插入发生在内部的情况(即左-右 or 右-左情况), 这种情况通过双旋转来处理;

2.3)单旋转(以图为荔枝)
2.3.1)左-左情况的单旋转: 把树形象地看成是柔软灵活的,抓住节点2 , 使劲摇动它, 在重力作用下, 节点2 就变成了新树的根;二叉查找树的性质告诉我们: 在原树中,节点3大于节点2, 所以在新树中,节点3要从成为节点2 的右儿子;(后面的情况以此类推)

  • Warning)要知道, 左左插入的情况下,不平衡树的左子树 或者有右孩子, 或者没有右孩子,但是我们在编程的时候,都要视为它有右孩子(因为即使算上,那也是NULL),所以首先要用 temp 来暂存不平衡树的左子树的右孩子, 最后还要把暂存的右孩子赋给根节点的左孩子(因为 不平衡树的左子树的所有节点值都小于不平衡树的根, 也顺便把不平衡树的左子树置空(可能的话));
  • souce code as follows:
AVLTree singleRotateLeftLeft(AVLTree root) // the case is left-left
{AVLTree temp; AVLTree left;   left = root->left;temp = left->right;left->right = root;root->left = temp;root->height = getHeight(root);     return left;
}

这里写图片描述
这里写图片描述
这里写图片描述
2.3.2)右-右情况的单旋转: 把树形象地看成是柔软灵活的,抓住节点4 , 使劲摇动它, 在重力作用下, 节点4 就变成了新树的根;二叉查找树的性质告诉我们: 在原树中,节点3小于节点4, 所以在新树中,节点4要从成为节点3 的左儿子;(后面的情况以此类推)

  • Warning)要知道, 右插入的情况下,不平衡树的右子树 或者有左孩子, 或者没有左孩子,但是我们在编程的时候,都要视为它有左孩子(因为即使算上,那也是NULL),所以首先要用 temp 来暂存不平衡树的右子树的左孩子, 最后还要把暂存的左孩子赋给根节点的右孩子(因为 不平衡树的右子树的所有节点值都大于不平衡树的根, 也顺便把不平衡树的右子树置空(可能的话));
  • souce code as follows:
 AVLTree singleRotateRightRight(AVLTree root) // the case is right-right
{AVLTree temp; AVLTree right;  right = root->right;temp = right->left;right->left = root;root->right = temp;root->height = max(getHeight(root->left), getHeight(root->right)) + 1;      return right;
}

这里写图片描述
这里写图片描述

2.4)双旋转:
2.4.1)左-右情况的双旋转(我们以下图插入节点9为荔枝):也即是对于不平衡 节点10 的左儿子 节点8 的右子树NULL 进行一次插入节点9:

  • step1)将 插入左儿子右子树的结构转换为 左儿子左子树的结构;
  • step2)将 左儿子左子树的结构进行 左-左单旋转;
  • souce code as follows:
AVLTree doubleRotateLeftRight(AVLTree root) // the case is left-right
{AVLTree temp;AVLTree right;temp = root->left;right = temp->right;root->left = right; // convert left-right into left-lefttemp->right = right->left;right->left= temp;temp->height = getHeight(temp);return singleRotateLeftLeft(root);  // the case is left-left
}

这里写图片描述

2.4.2)右-左情况的双旋转(我们以下图插入节点15为荔枝):也即是对于不平衡 节点7 的右儿子 节点16 的左子树NULL 进行一次插入节点15:

  • step1)将 插入右儿子左子树的结构转换为 右儿子右子树的结构;
  • step2)将 右儿子右子树的结构进行 右-右单旋转;

souce code as follows:

AVLTree doubleRotateRightLeft(AVLTree root) // the case is right-left
{AVLTree temp;AVLTree left;temp = root->right;left = temp->left;root->right = left; // convert right-left into right-righttemp->left = left->right;left->right = temp;temp->height = getHeight(temp);return singleRotateRightRight(root); // the case is right-right     
}

这里写图片描述
这里写图片描述
这里写图片描述


【3】source code

3.1)download source code: https://github.com/pacosonTang/dataStructure-algorithmAnalysis/blob/master/chapter4/p80_AVL_tree.c
3.2)source code at a glance :

#include <stdio.h>
#include <malloc.h>#define ElementType int
#define Error(str) printf("\n error: %s \n",str)   struct AVLTree;
typedef struct AVLTree *AVLTree;AVLTree createAVLTree(ElementType);
AVLTree makeEmpty(AVLTree);
AVLTree insert(ElementType, AVLTree) ;
AVLTree deleteAVLTree(ElementType e, AVLTree root);
ElementType Retrieve(AVLTree);AVLTree singleRotateLeftLeft(AVLTree root);
AVLTree singleRotateRightRight(AVLTree root);
AVLTree doubleRotateLeftRight(AVLTree root);
AVLTree doubleRotateRightLeft(AVLTree root);int getHeight(AVLTree root);// we adopt child-sibling notation
struct AVLTree
{ElementType value;AVLTree left;AVLTree right;int height;
};
//get the maximum
int max(int a, int b)
{return  a > b ? a : b;
}// get the height
int getHeight(AVLTree root)
{if(!root)return -1;elsereturn 1 + max(getHeight(root->left), getHeight(root->right));
}// create a AVLTree with root node
AVLTree createAVLTree(ElementType value)
{   AVLTree t;t = (AVLTree)malloc(sizeof(struct AVLTree));if(!t) {Error("out of space, from func createAVLTree");        return NULL;}    t->left = NULL;t->right = NULL;    t->value = value;t->height = 0;return t;
}// make the AVLTree empty 
AVLTree makeEmpty(AVLTree t)
{if(t){makeEmpty(t->left);makeEmpty(t->right);        free(t);}           return NULL;
}AVLTree doubleRotateLeftRight(AVLTree root) // the case is left-right
{AVLTree temp;AVLTree right;temp = root->left;right = temp->right;root->left = right; // convert left-right into left-lefttemp->right = right->left;right->left= temp;temp->height = getHeight(temp);return singleRotateLeftLeft(root);  // the case is left-left
}AVLTree doubleRotateRightLeft(AVLTree root) // the case is right-left
{AVLTree temp;AVLTree left;temp = root->right;left = temp->left;root->right = left; // convert right-left into right-righttemp->left = left->right;left->right = temp;temp->height = getHeight(temp);return singleRotateRightRight(root); // the case is right-right     
}AVLTree singleRotateLeftLeft(AVLTree root) // the case is left-left
{AVLTree temp; AVLTree left;   left = root->left;temp = left->right;left->right = root;root->left = temp;root->height = getHeight(root);     return left;
}AVLTree singleRotateRightRight(AVLTree root) // the case is right-right
{AVLTree temp; AVLTree right;  right = root->right;temp = right->left;right->left = root;root->right = temp;root->height = max(getHeight(root->left), getHeight(root->right)) + 1;      return right;
}AVLTree insert(ElementType e, AVLTree root) 
{           if(!root) {// find the node with its left or right being NULLroot = createAVLTree(e);if(root)  return root;                     else return NULL;}if(e > root->value) { root->right = insert(e, root->right); if(getHeight(root->right) - getHeight(root->left) == 2) { // after insertion, we should judge whether the tree is balanced or notif(e > root->right->value) // the case is right-rightroot = singleRotateRightRight(root);else    // the case is right-leftroot = doubleRotateRightLeft(root);}}else if(e < root->value) { root->left = insert(e, root->left); if(getHeight(root->left) - getHeight(root->right) == 2) { // after insertion, we should judge whether the tree is balanced or notif(e < root->left->value) // the case is left-leftroot = singleRotateLeftLeft(root);else    // the case is left-rightroot = doubleRotateLeftRight(root);}}elseError(" you cannot insert the node into the tree for its value equals to one in the tree");  root->height = max(getHeight(root->left), getHeight(root->right)) + 1; // after insertion, root's height increses one layerreturn root; // dont't forget this line !
}  // analog print directories and files name in the AVLTree, which involves postorder traversal. 
void printPreorder(int depth, AVLTree root)
{           int i;if(root) {      for(i = 0; i < depth; i++)printf("    ");     printf("%d\n", root->value);printPreorder(depth + 1, root->left);                                           printPreorder(depth + 1, root->right); // Attention: there's difference between traversing binary tree and common tree                          }else {for(i = 0; i < depth; i++)printf("    ");     printf("NULL\n");}
} int main()
{AVLTree root;       printf("\n ====== test for building the AVLTree ====== \n");            printf("\n [the left-left case] test for creating a AVL tree with inserting 3, 2, 1 in trun \n");   root = NULL;root = insert(3, root); root = insert(2, root); root = insert(1, root); printPreorder(1, root); printf("\n [the right-right case] test for inserting node '4' and '5' in turn \n");     insert(4, root);insert(5, root);printPreorder(1, root);          printf("\n [the right-right case] test for inserting node '6 in turn \n");      root = insert(6, root); printPreorder(1, root); printf("\n [the right-right case] test for inserting node '7' and '16' in turn \n");        root = insert(7, root);root = insert(16, root);printPreorder(1, root); printf("\n [the right-left case] test for inserting node '15' in turn \n");     root = insert(15, root);     printPreorder(1, root); printf("\n [the right-left case] test for inserting node '14' in turn \n");     root = insert(14, root);     printPreorder(1, root);     printf("\n [the right-left case] test for inserting node '13' in turn \n");     root = insert(13, root);     printPreorder(1, root); printf("\n [the left-left case] test for inserting node '12' in turn \n");      root = insert(12, root);     printPreorder(1, root); printf("\n [the left-left case] test for inserting node '11' and '10' in turn \n");     root = insert(11, root);     root = insert(10, root);     printPreorder(1, root); printf("\n [the left-left case] test for inserting node '8' in turn \n");       root = insert(8, root);  printPreorder(1, root); printf("\n [the left-right case] test for inserting node '9' in turn \n");      root = insert(9, root);  printPreorder(1, root);      return 0;
}

【4】printing result set

这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/332016.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

spring 注释_Spring@懒惰注释

spring 注释介绍&#xff1a; 默认情况下&#xff0c; Spring框架在应用程序启动时加载并热切初始化所有bean。 在我们的应用程序中&#xff0c;我们可能有一些非常消耗资源的bean。 我们宁愿根据需要加载此类bean。 我们可以使用Spring Lazy批注实现此目的 。 在本教程中&…

管理系统的账户设计(涉及注册/登录逻辑)

文章目录方案一方案二方案三方案一 类似华为云IAM&#xff08;Identity and Access Management 身份和访问管理&#xff09;用户&#xff0c;阿里云的 RAM&#xff08;Resource Access Management 资源访问管理&#xff09;用户 机构有独立的账户&#xff08;主账户&#xff…

opencv生成日志_OpenCV-Utils学习日志:VideoCapture使用样例

1.VideoCapture可以打开多种来源的数据流&#xff0c;但常见的是相机、视频及图像序列三类数据流&#xff1a;(1)打开相机数据流&#xff0c;需要指定相机在主机上的设备编号&#xff0c;若主机上只有一个相机则编号通常是0。(2)打开视频数据流&#xff0c;需要指定视频的完整路…

jdbc查询序列_JDBC –模拟序列

jdbc查询序列也许我们每个人在程序员的生活中至少遇到过一次这个问题- 如何模拟数据库序列&#xff1f; 在下面&#xff0c;您可能会发现我对该问题解决方案的各种了解。 假设我们有一个接口定义了所需的API&#xff0c;用于返回整数序列&#xff1a; public interface Sequen…

利用 GregorianCalendar 制作当前月的月历

【0】README 0.1&#xff09;本文文字总结于 core java volume 1 &#xff0c; 源代码均为原创&#xff1b; 0.2&#xff09;本文旨在熟悉 GregorianCalendar 日历类&#xff0c;每一天就是一个GregorianCalendar 日历类&#xff0c;一天有很多的日历属性&#xff0c;觉得用它…

pyecharts怎么绘制散点图_PyeCharts绘制各种图形

简介PyeCharts 是一个用于生成 Echarts 图表的类库&#xff0c;用其生成的图可视化效果非常棒&#xff0c;而且使用起来非常简单。下面是一些常用图的pyecharts实现方法柱状图bar pye.Bar("柱状图")#新建柱状图bar.add("服装", #图例名称["衬衫"…

junit junit_穿越JUnit流

junit junit关于JUnit 5迁移的好处之一是&#xff0c;您可以在老式模式下运行JUnit 4测试&#xff0c;并且所有内容仍然兼容。 不利的一面是&#xff0c;某些注释和方法在JUnit 4和JUnit 5中具有相同的名称&#xff0c;并且当两组库依赖项都可用时&#xff0c;很容易导入错误的…

被遗忘的软件产品形态

从2010年以后&#xff0c;很多公司开发的软件产品&#xff0c;很少有客户端了&#xff0c;web2.0之后&#xff0c;主流的业务系统基本上都是基于Web去构建业务系统。这几年见到的业务应用系统都是基于Web的构建的。而在To C市场&#xff0c;几乎就没有客户端了&#xff0c;都是…

vue进行判断使用class_vue判断dom的class

vue点击给dom添加class然后获取含有class的dom{{item.name}}{{item2.name}}jschek(index2, index) {this.iac[index2] indexthis.iac this.iac.concat([]);this.checkchose()},checkchose:function(){var chosethisvar chosedomchose.$refs.choseboxconsole.log(chosedom)for…

方法参数的值调用+引用调用+深浅拷贝

【0】README 0.1&#xff09;本文描述源代码均 转自 core java volume 1&#xff0c; 旨在理清值调用引用调用&#xff1b; 【1】参数传递给方法的专业术语&#xff1a; 1.1&#xff09;值调用&#xff1a;它表示方法接收的是调用者提供的值&#xff1b; 1.2&#xff09;引用…

设计模式 工厂方法_工厂方法设计模式

设计模式 工厂方法工厂方法模式是流行的创作设计模式之一。 它并不特别依赖于工厂对象来创建对象。 而是要在同一类中使用单独的方法来创建对象。 Factory Method模式定义了一个用于创建对象的接口&#xff0c;但是让子类决定如何实例化其对象。 每个子类必须定义其Factory方法…

靖江机器人怎么样_铁饭碗不保?靖江可能消失的12大职业!快看有你的工作没?...

原标题&#xff1a;铁饭碗不保&#xff1f;靖江可能消失的12大职业&#xff01;快看有你的工作没&#xff1f;无人飞机、无人驾驶、智能机器人....你能想象这些充满现代感的高科技正在改变我们的生活吗&#xff1f;在科技高速发展的今天人工智能逐渐能够代替人类的部分工作但&a…

MarkdownPad 汉化破解(含下载地址)

转自 http://jingyan.baidu.com/article/ca41422fe209271eaf99ed7c.html MarkdownPad是一个全功能Markdown编辑器的Windows。 【1】MarkdownPad 汉化破解&#xff08;含下载地址&#xff09; 工具/原料 MarkdownPad 2.4 方法/步骤 软件 下载地址&#xff08;本软件为绿色版…

捡对象引流脚本 内容_对象和索引流

捡对象引流脚本 内容我本来要写一篇关于如何将流与每个元素的索引混合的文章&#xff0c;但是Baeldung上的人们已经很好地涵盖了这个主题 &#xff01; 鉴于我是他们编辑团队的一员&#xff0c;我为他们/我们感到自豪。 有趣的是&#xff0c;特别是Streams中的Java函数式编程如…

散列之再散列

【0】README 0.1&#xff09;本文描述总结于 数据结构与算法分析&#xff0c; 但源代码为原创&#xff1b; 0.2&#xff09;为什么写这篇博文&#xff1f; 再散列的代码实现 包括了 解决冲突的方法实现&#xff1b;很有代表性&#xff1b;&#xff08;本源代码采用的解决冲突…

激活策略 查询_5个提问,详细介绍北极星指标的策略框架

北极星指标&#xff08;North Star Metric&#xff09;已经逐渐成为许多公司指导产品发展的重要指标&#xff0c;本文通过五个设问和多个行业案例&#xff0c;系统性地介绍北极星指标这类产品策略框架。如今有非常多的人在谈论和使用北极星指标&#xff08;North Star Metric&a…

变色龙嗅探卡功能_变色龙功能

变色龙嗅探卡功能在《神秘博士》中&#xff0c;卡梅利恩&#xff08;Kamelion&#xff09;角色是一个可以采取任何形式的机器人。 据称&#xff0c;他们使用的物理道具非常麻烦&#xff0c;只有其创建者才能理解&#xff0c;而该创建者并没有帮助纠正它。 因此&#xff0c;Cha…

老人与海好词100英文带翻译_《老人与海》经典语录(英文+译文)

《老人与海》是海明威于1951年在古巴写的一篇中篇小说&#xff0c;于1952年出版。是海明威最著名的作品之一。它围绕一位老年古巴渔夫&#xff0c;与一条巨大的马林鱼在离岸很远的湾流中搏斗而展开故事的讲述。它奠定了海明威在世界文学中的突出地位&#xff0c;这篇小说相继获…

java多态+多态中隐含的问题

【0】RAEDME 0.1&#xff09;本文总结于 core java volume 1&#xff0c; 感觉多态中存在的这个问题很新颖&#xff0c;故分享之&#xff1b; 【1】继承与is-a法则 1.1&#xff09;有一个用来判断是否应该设计为继承关系的规则&#xff1a; 这就是 is-a 规则&#xff0c; 它…

MacOS命令终端(CMD)的快捷键/终端快捷键

文章目录常用删除清屏复制粘贴交互/撤销移动光标查找历史命令使用命令查看历史命令标签页控制命令滚屏常用 快捷键说明Control A跳到本行的行首Control E跳到本行的行尾Control U删除光标前面&#xff08;左侧&#xff09;的所有文字&#xff08;还有剪切功能&#xff09;&…