从这位前辈的博客园中学习的数据结构:https://www.cnblogs.com/skywang12345/

非常感谢这位前辈。

以下文章摘录于 :skywang12345的博客园:转载请注明出处:http://www.cnblogs.com/skywang12345/p/3576969.html

及自我的一些理解。

首先介绍下AVL树:

  AVL树:二叉树的一种,其名为:平衡二叉查找树、高度平衡树。其表现形式为:AVL树中的任何节点的两个子树,它们的高度相差最大为1。即HEIGHT <= 1;

  如下图:

  AVL树的查找、插入和删除在平均和最坏情况下都是O(logn)。

  如果在AVL树中插入或删除节点后,使得高度之差大于1。此时,AVL树的平衡状态就被破坏,它就不再是一棵二叉树;为了让它重新维持在一个平衡状态,就需要对其进行旋转处理。学AVL树,重点的地方也就是它的旋转算法;

  AVL树失去平衡的几种情况:

  (1)

  

  (2)

  

  这种失去平衡的可以概括为4种姿态:LL(左左),LR(左右),RR(右右)和RL(右左)。

    LL: 失去平衡的节点为:左节点的左孩子,即左节点的左孩子也有了左(右)孩子

    LR: 失去平衡的节点为:左节点的右孩子,即左节点的右孩子也有了左(右)孩子

    RR: 失去平衡的节点为:右节点的右孩子,即右节点的右孩子也有了左(右)孩子

    RL: 失去平衡的节点为:右节点的左孩子,即右节点的左孩子也有了左(右)孩子

  0.定义

  

typedef struct AVLTreeNode{
Type key; //关键值
struct AVLTreeNode *left; //左孩子
struct AVLTreeNode *right; //右孩子
int height; //高度
}Node,*AVLTree;

//使用条件表达式时,最外面的大括号不能丢,如果丢了的话会造成数据的计算错误
#define AVL_HEIGHT(p) ( (p == NULL)?0:( ((AVLTree)(p))->height ) )
#define MAX(a,b) ( ((a) > (b) )? (a) : (b) )

  1.创建AVLTree的节点

  

AVLTree creatAVLTreeNode(Type key, AVLTree left, AVLTree right) //高度并不是人为决定的
{
AVLTree p;
if ((p = (AVLTree)malloc(sizeof(Node))) == NULL)
{
printf("malloc ERROR in %s\n",__FUNCTIONW__);
return ;
}
p->height = ;
p->key = key;
p->left = left;
p->right = right;
}

  2.获取AVLTree的高度

//获取AVLTree的高度
//树的高度为最大层次。即空的二叉树的高度是0,非空树的高度等于它的最大层次(根的层次为1,根的子节点为第2层,依次类推)。
int GetAVLTreeHeight(AVLTree tree)
{
return AVL_HEIGHT(tree);
}

  3.对于各种情况的旋转处理

/*
* LL:左左对应的情况(左单旋转)。 称为:右旋
*
* 返回值:旋转后的根节点
*/
static AVLTree left_left_rotation(AVLTree k2)
{
AVLTree k1; k1 = k2->left;
k2->left = k1->right;
k1->right = k2; k2->height = MAX((GetAVLTreeHeight(k2->left)), (GetAVLTreeHeight(k2->right))) +; //加上本身节点高度,根节点高度为1
k1->height = MAX((GetAVLTreeHeight(k1->left)),k2->height) + ; //加上本身节点高度,根节点高度为1 return k1;
} /*
* RR:右右对应的情况(右单旋转)。称为:左旋
*
* 返回值:旋转后的根节点
*/
static AVLTree right_right_rotation(AVLTree k1)
{
AVLTree k2; k2 = k1->right;
k1->right = k2->left;
k2->left = k1; k1->height = MAX( AVL_HEIGHT(k1->left), AVL_HEIGHT(k1->right) ) + ;
k2->height = MAX(k1->height, AVL_HEIGHT(k2->right)) + ;
return k2;
} /*
* LR:左右对应的情况(先右旋转,再左旋转)。
*
* 返回值:旋转后的根节点
*/
static AVLTree left_right_rotation(AVLTree k3)
{
//1. 进行 RR单旋转
k3->left = right_right_rotation(k3);
//2. 进行 LL单旋转
return left_left_rotation(k3);
} /*
* RL:右左对应的情况(先左旋转,再右旋转)。
*
* 返回值:旋转后的根节点
*/
static AVLTree right_left_rotation(AVLTree k3)
{
//1. 进行 LL单旋转
k3->left = left_left_rotation(k3);
//2. 进行 RR单旋转
return right_right_rotation(k3);
}

  4.插入

/*
* 3. 插入
* 将结点插入到AVL树中,并返回根节点
*
* 参数说明:
* tree AVL树的根结点
* key 插入的结点的键值
* 返回值:
* 根节点
*/
AVLTree avltree_insert(AVLTree tree, Type key)
{ if (tree == NULL) //如果树为空的,则将key作为根节点
{
if ((tree = creatAVLTreeNode(key, NULL, NULL)) == NULL)
{
printf("creatNode ERROR in %s \n",__FUNCTIONW__);
return NULL;
}
}
else if (key < tree->key) //根据二叉树特性,将key插入左节点
{
tree->left = avltree_insert(tree->left, key); //插入节点后,进行平衡树的检查
if (AVL_HEIGHT(tree->left) - AVL_HEIGHT(tree->right) == ) //因为插入的是左节点,所以是left-right;
{
if (key < tree->left->key) //判断是LR 还是LL;
tree = left_left_rotation(tree);
else
tree = left_right_rotation(tree);
}
}
else if (key > tree->key)
{
tree->right = avltree_insert(tree->right, key);
//插入节点后,进行平衡树的检查
if (AVL_HEIGHT(tree->right) - AVL_HEIGHT(tree->left) == )
{
if (key > tree->left->key) //判断是RR 还是RL;
tree = right_right_rotation(tree);
else
tree = right_left_rotation(tree);
}
}
else //(key == tree->key)
printf("添加失败:不允许添加相同的节点!\n"); tree->height = MAX(AVL_HEIGHT(tree->left),AVL_HEIGHT(tree->right)) + ;
return tree; }

  5.查找key值

//4.查找key值
AVLTree AVLTree_search(AVLTree tree, Type key)
{
if (tree == NULL || key == tree->key)
return tree;
if (key > tree->key)
return AVLTree_search(tree->right, key);
else
return AVLTree_search(tree->left, key);
} //5.查找最大值 与 最小值的节点
AVLTree AVLTreeMaxNode(AVLTree tree)
{
if (tree == NULL)
return NULL;
while (tree->right != NULL)
tree = tree->right;
return tree;
}
AVLTree AVLTreeMinNode(AVLTree tree)
{
if (tree == NULL)
return NULL;
while (tree->left != NULL)
tree = tree->left;
return tree;
}

  6.删除节点

/*
* 6.删除结点(z),返回根节点
*
* 参数说明:
* ptree AVL树的根结点
* z 待删除的结点
* 返回值:
* 根节点
*/
static AVLTree delete_node(AVLTree tree, AVLTree z)
{
// 根为空 或者 没有要删除的节点,直接返回NULL。
if (tree == NULL || z == NULL)
return NULL; if (z->key < tree->key) // 待删除的节点在"tree的左子树"中
{
tree->left = delete_node(tree->left,z); // 删除节点后,若AVL树失去平衡,则进行相应的调节。
if (AVL_HEIGHT(tree->right) - AVL_HEIGHT(tree->left) == )
{
Node *r = tree->right; //判断是哪种失去平衡情况:
//如果删除的节点在左子树中,则说明删除后就看根节点的右孩子里的情况就好,相当于第一个为Rx(先右旋,再x旋)
//如果左孩子的高度大于右孩子的根则是 RL,反之亦然,下同
if (AVL_HEIGHT(r->left) > AVL_HEIGHT(r->right))
tree = right_left_rotation(tree);
else
tree = right_right_rotation(tree);
}
}
else if (z->key > tree->key)// 待删除的节点在"tree的右子树"中
{
tree->right = delete_node(tree->right, z);
// 删除节点后,若AVL树失去平衡,则进行相应的调节。
if (AVL_HEIGHT(tree->left) - AVL_HEIGHT(tree->right) == )
{
Node *l = tree->left;
if (AVL_HEIGHT(l->right) > AVL_HEIGHT(l->left))
tree = left_right_rotation(tree);
else
tree = left_left_rotation(tree);
}
}
else // tree是对应要删除的节点。
{
if (tree->left && tree->right) //如果待删除的节点左右孩子都不为空
{
if (HEIGHT(tree->left) > HEIGHT(tree->right))
{
// 如果tree的左子树比右子树高;
// 则(01)找出tree的左子树中的最大节点
// (02)将该最大节点的值赋值给tree。
// (03)删除该最大节点。
// 这类似于用"tree的左子树中最大节点"做"tree"的替身;
// 采用这种方式的好处是:删除"tree的左子树中最大节点"之后,AVL树仍然是平衡的。
Node *max = AVLTreeMaxNode(tree->left);
tree->key = max->key;
tree->left = delete_node(tree->left, max);
}
else
{
// 如果tree的左子树不比右子树高(即它们相等,或右子树比左子树高1)
// 则(01)找出tree的右子树中的最小节点
// (02)将该最小节点的值赋值给tree。
// (03)删除该最小节点。
// 这类似于用"tree的右子树中最小节点"做"tree"的替身;
// 采用这种方式的好处是:删除"tree的右子树中最小节点"之后,AVL树仍然是平衡的。
Node *min = AVLTreeMinNode(tree->right);
tree->key = min->key;
tree->right = delete_node(tree->right, min);
}
}
}
}

  

数据结构之 AVL个人笔记的更多相关文章

  1. <数据结构与算法分析>读书笔记--最大子序列和问题的求解

    现在我们将要叙述四个算法来求解早先提出的最大子序列和问题. 第一个算法,它只是穷举式地尝试所有的可能.for循环中的循环变量反映了Java中数组从0开始而不是从1开始这样一个事实.还有,本算法并不计算 ...

  2. <数据结构与算法分析>读书笔记--运行时间计算

    有几种方法估计一个程序的运行时间.前面的表是凭经验得到的(可以参考:<数据结构与算法分析>读书笔记--要分析的问题) 如果认为两个程序花费大致相同的时间,要确定哪个程序更快的最好方法很可能 ...

  3. <数据结构与算法分析>读书笔记--函数对象

    关于函数对象,百度百科对它是这样定义的: 重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象.又称仿函数. 听起来确实很难懂,通过搜索我找到一篇 ...

  4. <数据结构与算法分析>读书笔记--利用Java5泛型实现泛型构件

    一.简单的泛型类和接口 当指定一个泛型类时,类的声明则包括一个或多个类型参数,这些参数被放入在类名后面的一对尖括号内. 示例一: package cn.generic.example; public ...

  5. linux 内核数据结构之 avl树.

    转载: http://blog.csdn.net/programmingring/article/details/37969745 https://zh.wikipedia.org/wiki/AVL% ...

  6. 数据结构之AVL树

    AVL树是高度平衡的而二叉树.它的特点是:AVL树中任何节点的两个子树的高度最大差别为1. 旋转 如果在AVL树中进行插入或删除节点后,可能导致AVL树失去平衡.这种失去平衡的可以概括为4种姿态:LL ...

  7. AVL学习笔记

    AVL,平衡二叉查找树.删除,插入,查找的复杂度都是O(logn).它是一棵二叉树.对于每个节点来说,它的左孩子的键值都小于它,右孩子的键值都大于它.对于任意一个节点,它的左右孩子的高度差不大于1.树 ...

  8. [算法] 数据结构之AVL树

    1 .基本概念 AVL树的复杂程度真是比二叉搜索树高了整整一个数量级——它的原理并不难弄懂,但要把它用代码实现出来还真的有点费脑筋.下面我们来看看: 1.1  AVL树是什么? AVL树本质上还是一棵 ...

  9. D&F学数据结构系列——AVL树(平衡二叉树)

    AVL树(带有平衡条件的二叉查找树) 定义:一棵AVL树是其每个节点的左子树和右子树的高度最多差1的二叉查找树. 为什么要使用AVL树(即为什么要给二叉查找树增加平衡条件),已经在我之前的博文中说到过 ...

随机推荐

  1. 【Leetcode】【Medium】Repeated DNA Sequences

    All DNA is composed of a series of nucleotides abbreviated as A, C, G, and T, for example: "ACG ...

  2. CVE-2013-3897漏洞成因与利用分析

    CVE-2013-3897漏洞成因与利用分析 1. 简介 此漏洞是UAF(Use After Free)类漏洞,即引用了已经释放的内存.攻击者可以利用此类漏洞实现远程代码执行.UAF漏洞的根源源于对对 ...

  3. 重新认识KCP

    什么是KCP KCP是一种网络传输协议(ARQ,自动重传请求),可以视它为TCP的代替品,但是它运行于用户空间,它不管底层的发送与接收,只是个纯算法实现可靠传输,它的特点是牺牲带宽来降低延迟.因为TC ...

  4. 设计模式:备忘录(Memento)模式

    设计模式:备忘录(Memento)模式 一.前言   备忘录模式用于保存和恢复对象的状态,相信大家看过我前面的拙作就会想到原型模式也能保存一个对象在某一个时刻的状态,那么两者有何不同的呢?原型模式保存 ...

  5. 获取所有权windows目录所有权

    Takeown /r /f 盘符:\目录\目录 例如: Takeown /r /f C:\Windows\CSC

  6. EJB 3.1 @Startup @Singleton sequence

    The annotation javax.ejb.Startup (@Startup) is used to mark an EJB so to make the EJB can be brought ...

  7. 实验5&期中考试后两题

    实验内容1: #include <iostream> #include <vector> #include <string> using namespace std ...

  8. NODE-环境变量的配置(踩坑总结)

    初学Node.js,从官网下载了node.js的Windows Installer,安装完成后,通过控制台输入node命令,发现提示说“node"不是内部或外部命令,这通常是由于没有设置环境 ...

  9. SDR窃听-监听空中的无线电

    A GSM HACK的另一种方法:RTL-SDR 0x00 背景 文中所有内容仅供学习研究,请勿用于非法用途.在绝大多数国家里非法窃听都是严重非法行为. 本文内容只讨论GSM数据的截获,不讨论破解. ...

  10. 牛客网多校训练第三场 C - Shuffle Cards(Splay / rope)

    链接: https://www.nowcoder.com/acm/contest/141/C 题意: 给出一个n个元素的序列(1,2,...,n)和m个操作(1≤n,m≤1e5),每个操作给出两个数p ...