本文实例讲述了C语言数据结构之平衡二叉树(AVL树)实现方法。分享给大家供大家参考,具体如下:

AVL树是每个结点的左子树和右子树的高度最多差1的二叉查找树。

要维持这个树,必须在插入和删除的时候都检测是否出现破坏树结构的情况。然后立刻进行调整。

看了好久,网上各种各种的AVL树,千奇百怪。

关键是要理解插入的时候旋转的概念。

//

// AvlTree.h

// HelloWorld

// Created by feiyin001 on 17/1/9.

// Copyright (c) 2017年 FableGame. All rights reserved.

//

#ifndef __HelloWorld__AvlTree__

#define __HelloWorld__AvlTree__

#include

namespace Fable

{

int max(int a, int b)

{

return a > b? a:b;

}

//二叉查找树,对于Comparable,必须实现了><=的比较

template

class AvlTree

{

public:

//构造函数

AvlTree(){}

//复制构造函数

AvlTree(const AvlTree& rhs)

{

root = clone(rhs.root);

}

//析构函数

~AvlTree()

{

makeEmpty(root);

}

//复制赋值运算符

const AvlTree& operator=(const AvlTree& rhs)

{

if (this != &rhs)

{

makeEmpty(root);//先清除

root = clone(rhs.root);//再复制

}

return *this;

}

//查找最小的对象

const Comparable& findMin()const

{

findMin(root);

}

//查找最大的对象

const Comparable& findMax()const

{

findMax(root);

}

//是否包含了某个对象

bool contains(const Comparable& x)const

{

return contains(x, root);

}

//树为空

bool isEmpty()const

{

return root == nullptr;

}

//打印整棵树

void printTree()const

{

printTree(root);

}

//清空树

void makeEmpty()

{

makeEmpty(root);

}

//插入某个对象

void insert(const Comparable& x)

{

insert(x, root);

}

//移除某个对象

void remove(const Comparable& x)

{

remove(x, root);

}

private:

struct AvlNode

{

Comparable element;

AvlNode* left;

AvlNode* right;

int height;

AvlNode(const Comparable& theElement, AvlNode* lt, AvlNode* rt, int h = 0)

:element(theElement), left(lt), right(rt), height(h){}

};

typedef AvlNode* AvlNodePtr;

AvlNodePtr root;//根结点

//顺时针旋转

void clockwiseRotate(AvlNodePtr& a)

{

AvlNodePtr b = a->left;//左叶子

a->left = b->right;//a的左叶子变为b的右叶子,b本来的子结点都比a小的。

b->right = a;//b的右结点指向a,b的高度上升了。

a->height = max(height(a->left), height(a->right)) + 1;//重新计算a的高度

b->height = max(height(b->left), a->height) + 1;//重新计算b的高度

a = b;//a的位置现在是b,当前的根结点

}

//逆时针旋转

void antiClockWiseRotate(AvlNodePtr& a)

{

AvlNodePtr b = a->right;//右结点

a->right = b->left;//a接收b的左结点

b->left = a;//自己成为b的左结点

a->height = max(height(a->left), height(a->right)) + 1;//计算高度

b->height = max(b->height, height(a->right)) + 1;//计算高度

a = b;//新的根结点

}

//对左边结点的双旋转

void doubleWithLeftChild(AvlNodePtr& k3)

{

antiClockWiseRotate(k3->left);//逆时针旋转左结点

clockwiseRotate(k3);//顺时针旋转自身

}

//对右边结点的双旋转

void doubleWithRightChild(AvlNodePtr& k3)

{

clockwiseRotate(k3->right);//顺时针旋转有节点

antiClockWiseRotate(k3);//逆时针旋转自身

}

//插入对象,这里使用了引用

void insert(const Comparable& x, AvlNodePtr& t)

{

if (!t)

{

t = new AvlNode(x, nullptr, nullptr);

}

else if (x < t->element)

{

insert(x, t->left);//比根结点小,插入左边

if (height(t->left) - height(t->right) == 2)//高度差达到2了

{

if (x < t->left->element)//插入左边

{

clockwiseRotate(t);//顺时针旋转

}

else

{

doubleWithLeftChild(t);//双旋转

}

}

}

else if (x > t->element)

{

insert(x, t->right);//比根结点大,插入右边

if (height(t->right) - height(t->left) == 2)//高度差达到2

{

if (t->right->element < x)//插入右边

{

antiClockWiseRotate(t);//旋转

}

else

{

doubleWithRightChild(t);//双旋转

}

}

}

else

{

//相同的

}

t->height = max(height(t->left), height(t->right)) + 1;//计算结点的高度

}

void removeMin(AvlNodePtr& x, AvlNodePtr& t)const

{

if (!t)

{

return;//找不到

}

if (t->left)

{

removeMin(t->left);//使用了递归的方式

}

else

{

//找到最小的结点了

x->element = t->element;

AvlNodePtr oldNode = t;

t = t->right;

delete oldNode;//删除原来要删除的结点

}

if (t)

{

t->height = max(height(t->left), height(t->right)) + 1;//计算结点的高度

if(height(t->left) - height(t->right) == 2)

{ //如果左儿子高度大于右儿子高度

if(height(t->left->left) >= height(t->left->right))//并且左儿子的左子树高度大于左儿子的右子树高度

{

clockwiseRotate(t); //顺时针旋转

}

else

{

doubleWithLeftChild(t);//双旋转左子树

}

}

else

{

if(height(t->right->right) - height(t->right->left) == 2) //如果右子树大于左子树

{

antiClockWiseRotate(t);//逆时针旋转

}

else

{

doubleWithRright(t);//双旋转右子树

}

}

}

}

//删除某个对象,这里必须要引用

void remove(const Comparable& x, AvlNodePtr& t)const

{

if (!t)

{

return;//树为空

}

else if (x < t->element)

{

remove(x, t->left);//比根结点小,去左边查找

}

else if (x > t->element)

{

remove(x, t->right);//比根结点大,去右边查找

}

else if (!t->left && !t->right)//找到结点了,有两个叶子

{

removeMin(t, t->right);//这里选择的方法是删除右子树的最小的结点

}

else

{

AvlNodePtr oldNode = t;

t = (t->left) ? t->left : t->right;//走到这里,t最多只有一个叶子,将t指向这个叶子

delete oldNode;//删除原来要删除的结点

}

if (t)

{

t->height = max(height(t->left), height(t->right)) + 1;//计算结点的高度

if(height(t->left) - height(t->right) == 2)

{ //如果左儿子高度大于右儿子高度

if(height(t->left->left) >= height(t->left->right))//并且左儿子的左子树高度大于左儿子的右子树高度

{

clockwiseRotate(t); //顺时针旋转

}

else

{

doubleWithLeftChild(t);//双旋转左子树

}

}

else

{

if(height(t->right->right) - height(t->right->left) == 2) //如果右子树大于左子树

{

antiClockWiseRotate(t);//逆时针旋转

}

else

{

doubleWithRright(t);//双旋转右子树

}

}

}

}

//左边子树的结点肯定比当前根小的,所以一直往左边寻找

AvlNodePtr findMin(AvlNodePtr t)const

{

if (!t)

{

return nullptr;//找不到

}

if (!t->left)

{

return t;

}

return findMin(t->left);//使用了递归的方式

}

//右边子树的结点肯定比当前根大,所以一直往右边找

AvlNodePtr findMax(AvlNodePtr t)const

{

if (t)

{

while (t->right)//使用了循环的方式

{

t = t->right;

}

}

return t;

}

//判断是否包含某个对象,因为要使用递归,所以还有一个public版本的

bool contains(const Comparable& x, AvlNodePtr t)const

{

if (!t)

{

return false;//空结点了

}

else if (x < t->element)

{

//根据二叉树的定义,比某个结点小的对象,肯定只能存在与这个结点的左边的子树

return contains(x, t->left);

}

else if (x > t->element)

{

//根据二叉树的定义,比某个结点大的对象,肯定只能存在与这个结点的右边的子树

return contains(x, t->right);

}

else

{

//相等,就是找到啦。

return true;

}

}

//清空子树

void makeEmpty(AvlNodePtr& t)

{

if (t)

{

makeEmpty(t->left);//清空左边

makeEmpty(t->right);//清空右边

delete t;//释放自身

}

t = nullptr;//置为空

}

//打印子树,这里没有使用复杂的排位,纯属打印

void printTree(AvlNodePtr t)const

{

if (!t)

{

return;

}

std::cout << t->element << std::endl;//输出自身的对象

printTree(t->left);//打印左子树

printTree(t->right);//打印右子树

}

AvlNodePtr clone(AvlNodePtr t)const

{

if (!t)

{

return nullptr;

}

return new AvlNode(t->element, clone(t->left), clone(t->right));

}

int height(AvlNodePtr t)const

{

return t == nullptr ? -1 : t->height;

}

};

}

#endif

简单测试一下。

//

// AvlTree.cpp

// HelloWorld

// Created by feiyin001 on 17/1/9.

// Copyright (c) 2017年 FableGame. All rights reserved.

//

#include "AvlTree.h"

using namespace Fable;

int main(int argc, char* argv[])

{

AvlTree a;

for(int i = 0; i < 100; ++i)

{

a.insert(i);

}

return 0;

}

这个删除的方法完全是自己写的,可能不是很高效。

希望本文所述对大家C语言程序设计有所帮助。

平衡查找树C语言程序,C语言数据结构之平衡二叉树(AVL树)实现方法示例相关推荐

  1. c语言——程序出现C4996:scanf 等错误的解决方法

    c语言--程序出现C4996:scanf 等错误的解决方法(不用scanf_s替换解决) 问题实例 解决方法 方法1 方法2 在VS编译器下,编写的c语言程序在调试编译时可能会出现c4996警告或错误 ...

  2. Python数据结构11:树的实现,树的应用,前中后序遍历,二叉查找树BST,平衡二叉树AVL树,哈夫曼树和哈夫曼编码

    1.概念 树一种基本的"非线性"数据结构. 相关术语: 节点Node:组成树的基本部分.每个节点具有名称,或"键值",节点还可以保存额外数据项,数据项根据不同的 ...

  3. 平衡二叉树,AVL树之图解篇

    学习过了二叉查找树,想必大家有遇到一个问题.例如,将一个数组{1,2,3,4}依次插入树的时候,形成了图1的情况.有建立树与没建立树对于数据的增删查改已经没有了任何帮助,反而增添了维护的成本.而只有建 ...

  4. 数据结构-平衡二叉树(AVL树)

    目录 1,平衡二叉树的介绍 1.1,二叉排序树存在的问题 1.2,平衡二叉树 1.3,平衡二叉树的创建 1.4,平衡二叉树的查找 2,代码实现 2.1,平衡二叉树的节点类型 2.2,LL旋转(单右旋转 ...

  5. 实现平衡二叉树(AVL树)的旋转

    给你一个数列{1,2,3,4,5,6},要求创建一颗二叉排序树(BST), 并分析问题所在. 左边 BST 存在的问题分析:               1) 左子树全部为空,从形式上看,更像一个单链 ...

  6. 数据结构与算法——AVL树类的C++实现

    关于AVL树的简单介绍能够參考: 数据结构与算法--AVL树简单介绍 关于二叉搜索树(也称为二叉查找树)能够參考:数据结构与算法--二叉查找树类的C++实现 AVL-tree是一个"加上了额 ...

  7. Java数据结构——平衡二叉树(AVL树)

    AVL树的引入 搜索二叉树有着极高的搜索效率,但是搜索二叉树会出现以下极端情况: 这样的二叉树搜索效率甚至比链表还低.在搜索二叉树基础上出现的平衡二叉树(AVL树)就解决了这样的问题.当平衡二叉树(A ...

  8. 文件的记录c语言程序,c语言程序学生籍贯信息记录簿设计.docx

    c 语言程序学生籍贯信息记录簿设计 学生籍贯信息记录簿 课程设计报告书 班 级: 方 0909-1 学 号:姓 名: 苑 小 叶 指导教师 : 康 亚 男 石家庄铁道大学四方学院 2010年 07月 ...

  9. 框图c语言程序,C语言程序设计框图

    <C语言程序设计框图>由会员分享,可在线阅读,更多相关<C语言程序设计框图(86页珍藏版)>请在人人文库网上搜索. 1.第三章控制结构,返回总目录,目录,3.1节目结构框,3. ...

最新文章

  1. html5页面默认的字符集是什么,HTML 字符集
  2. 用户运营的三种思维层级,你在哪一层?
  3. PHP于js的交互,关于php与js交互问题
  4. 爬虫时安装的newspaper 新闻包
  5. oracle11g scn 补丁,Oracle11g中SCN与TimeStamp的相互转换
  6. 计算机网络学习笔记(10. 速率、带宽、延迟)
  7. java发送jsp表格邮件_JSP 发送邮件
  8. 如何学习一个新的系统
  9. python 设备ArtNetToDMX512的协议测试
  10. Java基础案例教程———【任务4-2】模拟物流快递系统
  11. Java猫叫的方式,以【猫叫、老鼠跑、主人醒】为例子,使用 javascript 来实现 观察者模式 (有在线演示)...
  12. 启动mongo数据库
  13. mac python3 调用 .so_Mac OS X链接.so文件到动态库
  14. NDN命名网络工作机制和优点
  15. java中高效遍历list_Java中四种遍历List的方法总结(推荐)
  16. Nginx反向代理服务
  17. google play连接超时_Google以2亿美元收购Fitbit
  18. (翻译)Pachyderm介绍-建造一个现代的Hadoop
  19. python数据匹配,Excel
  20. “打开ftp服务器上的文件夹时发生错误,请检查是否有权限访问该文件夹“

热门文章

  1. 项目如何开始:怎样和客户一起搞定需求
  2. Go 神坑 1 —— interface{} 与 nil 的比较
  3. 虚拟网络VDC与VPC
  4. 来自intlsy‘s省选debug方法
  5. BZOJ #3746: [POI2015]Czarnoksiężnicy okrągłego stołu 动态规划
  6. linux_network
  7. 【MVC5】对MySql数据库使用EntityFramework
  8. linux之软连接和硬连接的区别
  9. Spring Boot2.0 整合mybatis、分页插件、druid
  10. MVC+EF 入门教程(四)