平衡二叉查找树

平衡二叉查找树是非常早出现的平衡树,由于全部子树的高度差不超过1,所以操作平均为O(logN)。

平衡二叉查找树和BS树非常像,插入和删除操作也基本一样。可是每一个节点多了一个高度的信息。在每次插入之后都要更新树的每一个节点的高度。发现不平衡之后就要进行旋转。

单旋转

单旋转是碰到左左或者右右的情况下所使用的方法。

比如:


  3
\
2
\
1

这样的情况就须要旋转,由于3是根节点,它的左子树高度为0,右子树高度为2。相差超过1了。所以要进行旋转。而这是右右的情况,所以是单旋转。


       2
/ \
1 3

这样子旋转过后就能够了~

双旋转

双旋转也非常easy,但代码操作会略微麻烦一点:


  2
\
4
/
3

遇到这样的情况就是双旋转,由于3是在2 4之间的。

旋转过后:


  3
/ \
2 4

这样子就能够了。。

事实上非常多时候情况比这个复杂,可是本质都是这样子操作的。

实现代码:

//
// AVL.h
// AVL
//
// Created by Alps on 14-8-7.
// Copyright (c) 2014年 chen. All rights reserved.
// #ifndef AVL_AVL_h
#define AVL_AVL_h #define ElementType int struct TreeNode;
typedef TreeNode* AVL;
typedef TreeNode* Position; Position Find(ElementType key, AVL A);
Position FindMax(AVL A);
Position FindMin(AVL A); AVL Insert(ElementType key, AVL A);
AVL Delete(ElementType key, AVL A); struct TreeNode{
ElementType element;
AVL left;
AVL right;
int height;
}; #endif

上面的代码是AVL.h文件。


//
// main.cpp
// AVL
//
// Created by Alps on 14-8-7.
// Copyright (c) 2014年 chen. All rights reserved.
// #include <iostream>
#include "AVL.h" int Height(AVL A){//求节点高度
if (A == NULL) {
return -1;
}else{
return A->height;
}
}
int MAX(int a, int b){//返回两数中的大数
return a>b? a:b;
} AVL SingleRotateWithRight(AVL A){//右单旋转
AVL tmp = A->right;
A->right = tmp->left;
tmp->left = A;
A->height = MAX(Height(A->left), Height(A->right))+1;
tmp->height = MAX(Height(tmp->left), Height(tmp->right))+1;
return tmp;
} AVL DoubleRotateWithRight(AVL A){//右双旋转
AVL tmp = A->right;
AVL tmp1 = tmp->left;
tmp->left = tmp1->right;
A->right = tmp1->left;
tmp1->right = tmp;
tmp1->left = A;
tmp->height = MAX(Height(tmp->left), Height(tmp->right))+1;
A->height = MAX(Height(A->left), Height(A->right))+1;
tmp1->height = MAX(Height(tmp1->left), Height(tmp1->right))+1;
return tmp1;
} AVL SingleRotateWithLeft(AVL A){//左单旋转
AVL tmp = A->left;
A->left = tmp->right;
tmp->right = A;
A->height = MAX(Height(A->left), Height(A->right))+1;
tmp->height = MAX(Height(tmp->left), Height(tmp->right))+1;
return tmp;
} AVL DoubleRotateWithLeft(AVL A){//左双旋转
AVL tmp = A->left;
AVL tmp1 = tmp->right;
tmp->right = tmp1->left;
A->left = tmp1->right;
tmp1->left = tmp;
tmp1->right = A;
tmp->height = MAX(Height(tmp->left), Height(tmp->right))+1;
A->height = MAX(Height(A->left), Height(A->right))+1;
tmp1->height = MAX(Height(tmp1->left), Height(tmp1->right))+1;
return tmp1;
} AVL Insert(ElementType key, AVL A){//插入元素
if (A == NULL) {
A = (AVL)malloc(sizeof(struct TreeNode));
A->element = key;
A->height = 0;
A->right = NULL;
A->left = NULL;
// return A;
}else{
if (key > A->element) {//假设大于当前节点,向右子树插入
A->right = Insert(key, A->right);
if (Height(A->right) - Height(A->left) == 2) {
if (key > A->right->element) {//假设插入到节点的右子树的右方,右单旋转
A = SingleRotateWithRight(A);
}else{
A = DoubleRotateWithRight(A);//插入到当前节点右子树的左方,右双旋转
}
} }else
if (key < A->element) {
A->left = Insert(key, A->left);
if (Height(A->left) - Height(A->right) == 2) {
if (key < A->left->element) {//左单旋转
A = SingleRotateWithLeft(A);
}else{
A = DoubleRotateWithLeft(A);
}
}
}
} A->height = MAX(Height(A->left), Height(A->right))+1;
return A;
} Position FindMax(AVL A){//找到当前树的最大值
AVL tmp = A;
if (A == NULL) {
return NULL;
}else{
while (tmp->right != NULL) {
tmp = tmp->right;
}
}
return tmp;
} Position FindMin(AVL A){//找到当前树的最小值
AVL tmp = A;
if (A == NULL) {
return NULL;
}else{
while (tmp->left != NULL) {
tmp = tmp->left;
}
}
return tmp;
} Position Find(ElementType key,AVL A){//查找节点,返回节点指针
AVL tmp = A;
if (A == NULL) {
return NULL;
}else{
while (tmp != NULL && tmp->element != key) {
if (key > tmp->element) {
tmp = tmp->right;
}else{
tmp = tmp->left;
}
}
}
return tmp;
} AVL Delete(ElementType key, AVL A){//删除节点 if (A == NULL || Find(key, A) == NULL) {
return NULL;
}else{ if (key == A->element) {//假设找到了要删除的节点
AVL tmp;
if (A->left && A->right) {//假设要删除的节点有左右子树
tmp = FindMin(A->left);//用当前节点左子树的最小值替换
A->element = tmp->element;
A->left = Delete(A->element, A->left);//删掉左子树最小值节点
}else{
tmp = A;
if (A->left) {
A = A->left;//<span style="font-family: Arial, Helvetica, sans-serif;">假设仅仅存在左子树,直接返回它的左子树节点</span> }else{
if (A->right) {
A = A->right; //<span style="font-family: Arial, Helvetica, sans-serif;">假设仅仅存在右子树。直接返回它的右子树节点</span> }else{
A = NULL;//删除的是叶子节点,直接赋值为NULL
}
}
free(tmp);
tmp = NULL;
return A;//返回删除后的节点
}
}else{
if (key > A->element) {//假设大于,去右子树
A->right = Delete(key, A->right);
if (Height(A->left) - Height(A->right) == 2) {
if (A->left->right != NULL && (Height(A->left->right) > Height(A->left->left))) {//假设当前节点不平衡。且节点左孩子存在右孩子,双旋转
A = DoubleRotateWithLeft(A);
}else{
A = SingleRotateWithLeft(A);//否则单旋转
}
}
// A->height = MAX(Height(A->left), Height(A->right));
}else{
if (key < A->element) {
A->left = Delete(key, A->left);
if (Height(A->right) - Height(A->left) == 2) {
if (A->right->left != NULL && (Height(A->right->left) > Height(A->right->right))) {//
A = DoubleRotateWithRight(A);
}else{
A = SingleRotateWithRight(A);
}
}
// A->height = MAX(Height(A->left), Height(A->right));
}
}
}
}
A->height = MAX(Height(A->left), Height(A->right))+1;
return A;
} int main(int argc, const char * argv[])
{
AVL A = NULL;
A = Insert(3, A);
printf("%d %d\n",A->element,A->height);
A = Insert(2, A);
printf("%d %d\n",A->left->element,A->height);
A = Insert(1, A);
printf("%d %d\n",A->left->element,A->left->height);
A = Insert(4, A);
A = Insert(5, A);
printf("%d %d\n",A->right->element,A->right->height);
A = Insert(6, A);
printf("%d %d\n",A->element,A->height);
A = Insert(7, A);
A = Insert(16, A);
A = Insert(15, A);
printf("%d %d\n",A->right->element,A->right->height);
A = Insert(14, A);
printf("%d %d\n",A->right->element,A->right->height);
A = Delete(16, A);
printf("%d %d\n",A->right->element,A->right->height);
A = Delete(6, A);
A = Delete(5, A);
printf("%d %d\n",A->right->element,A->right->height);
return 0;
}

算法学习 - 平衡二叉查找树实现(AVL树)的更多相关文章

  1. 数据结构与算法16—平衡二叉(AVL)树

    我们知道,对于一般的二叉搜索树(Binary Search Tree),其期望高度(即为一棵平衡树时)为log2n,其各操作的时间复杂度O(log2n)同时也由此而决定.但是,在某些极端的情况下(如在 ...

  2. 深入浅出数据结构C语言版(12)——平衡二叉查找树之AVL树

    在上一篇博文中我们提到了,如果对普通二叉查找树进行随机的插入.删除,很可能导致树的严重不平衡 所以这一次,我们就来介绍一种最老的.可以实现左右子树"平衡效果"的树(或者说算法),即 ...

  3. 平衡二叉查找树(AVL)的理解与实现

    AVL树的介绍 平衡二叉树,又称AVL(Adelson-Velskii和Landis)树,是带有平衡条件的二叉查找树.这个平衡条件必须要容易保持,而且它必须保证树的深度是 O(log N).一棵AVL ...

  4. 二叉查找树,AVL树,伸展树【CH4601普通平衡树】

    最近数据结构刚好看到了伸展树,在想这个东西有什么应用,于是顺便学习一下. 二叉查找树(BST),对于树上的任意一个节点,节点的左子树上的关键字都小于这个节点的关键字,节点的右子树上的关键字都大于这个节 ...

  5. 【Java】 大话数据结构(12) 查找算法(3) (平衡二叉树(AVL树))

    本文根据<大话数据结构>一书及网络资料,实现了Java版的平衡二叉树(AVL树). 平衡二叉树介绍 在上篇博客中所实现的二叉排序树(二叉搜索树),其查找性能取决于二叉排序树的形状,当二叉排 ...

  6. 常见基本数据结构——树,二叉树,二叉查找树,AVL树

    常见数据结构——树 处理大量的数据时,链表的线性时间太慢了,不宜使用.在树的数据结构中,其大部分的运行时间平均为O(logN).并且通过对树结构的修改,我们能够保证它的最坏情形下上述的时间界. 树的定 ...

  7. 数据结构——二叉查找树、AVL树

    二叉查找树:由于二叉查找树建树的过程即为插入的过程,所以其中序遍历一定为升序排列! 插入:直接插入,插入后一定为根节点 查找:直接查找 删除:叶子节点直接删除,有一个孩子的节点删除后将孩子节点接入到父 ...

  8. 算法二叉搜索树之AVL树

    最近学习了二叉搜索树中的AVL树,特在此写一篇博客小结. 1.引言 对于二叉搜索树而言,其插入查找删除等性能直接和树的高度有关,因此我们发明了平衡二叉搜索树.在计算机科学中,AVL树是最先发明的自平衡 ...

  9. 数据结构-自平衡二叉查找树(AVL)详解

    介绍: 在计算机科学中,AVL树是最先发明的自平衡二叉查找树. 在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树. 查找.插入和删除在平均和最坏情况下都是O(log n).增 ...

随机推荐

  1. java 多线程总结篇2之——Thread类及常用函数

    此片文章主要总结的是Thread类及相关的基础概念和API,首先需要厘清线程调度中的几个基本概念: 一.线程调度的基本方法 1.调整线程优先级:Java线程有优先级,优先级高的线程会获得较多的运行机会 ...

  2. SQL 标量函数-----日期函数 day() 、month()、year()

    select day(createtime) from life_unite_product --取时间字段的天值 select month(createtime) from life_unite_p ...

  3. 打印数据的字节(十六进制)表示-c语言代码

    先取数据地址,转换成单字节长度的类型(unsigned char)的指针,然后按照十六进制逐字节打印即可,格式为“%.2x”. sizeof()函数获取数据的字节数. /* $begin show-b ...

  4. ZooKeeper实践:(1)集群管理

    前言: 随着业务的扩大,用户的增多,访问量的增加,单机模式已经不能支撑,从而出现了从单机模式->垂直应用模式->集群模式,集群模式诞生了,伴随着一堆问题也油然而生,Master怎么选举,机 ...

  5. Adapter.notifyDataSetChanged()源码分析以及与ListView.setAdapter的区别

    一直很好奇,notifyDataSetChanged究竟是重绘了整个ListView还是只重绘了被修改的那些Item,它与重新设置适配器即调用setAdapter的区别在哪里?所以特地追踪了一下源码, ...

  6. C++11线程池的实现

    什么是线程池 处理大量并发任务,一个请求一个线程来处理请求任务,大量的线程创建和销毁将过多的消耗系统资源,还增加了线程上下文切换开销. 线程池通过在系统中预先创建一定数量的线程,当任务请求到来时从线程 ...

  7. 洛谷P3527 [POI2011]MET-Meteors [整体二分]

    题目传送门 Meteors 格式难调,题面就不妨放了. 分析: 一道整体二分的练手题. 就是一般的整体二分的套路,但是要注意,将修改和询问加入队列的时候要先加修改再加询问.另外,博主代码打得太丑,常数 ...

  8. CSUOJ 1008 Horcrux

    Description A Horcrux is an object in which a Dark wizard or witch has hidden a fragment of his or h ...

  9. Javap -c 字节码解析

              栈和局部变量操作 将常量压入栈的指令 aconst_null         将null对象引用压入栈   iconst_m1         将int类型常量-1压入栈 icon ...

  10. ICMP隧道工具ptunnel

    ICMP隧道工具ptunnel   在一些网络环境中,如果不经过认证,TCP和UDP数据包都会被拦截.如果用户可以ping通远程计算机,就可以尝试建立ICMP隧道,将TCP数据通过该隧道发送,实现不受 ...