《数据结构与算法分析》学习笔记(五)——二叉树
(一)查找二叉树ADT
1、二叉查找树ADT性质:
对于树中的每个节点X,它的左子树中所有关键字值都小于X的关键字值,而它的右子树值的关键字值都大于X的关键字值。
2、一些ADT的基本操作
结构定义
typedef int SearchTree_ElementType; struct SearchTreeNode; //这句话一定要加,要不下面这句不会成立。
typedef struct SearchTreeNode* SearchTree; struct SearchTreeNode
{
SearchTree_ElementType Element;
SearchTree Left;
SearchTree Right;
};
(1)建立空树:
一般来说空树有些人习惯用保留一个空的节点,但是按照标准定义的话,树理应为NULL,采用后者。(附简单代码,复习递归思路)
//清空树
SearchTree SearchTree_MakeEmpty(SearchTree Root)
{
if (Root != NULL)
{
SearchTree_MakeEmpty(Root->Left);
SearchTree_MakeEmpty(Root->Right);
delete Root;
}
return NULL;
}
(2)Find
使用简单递归思想写,代码简单,但是空间栈比较多,但是因为深度为logN,所以应该空间是可以接受的。
SearchTree_Position SearchTree_Find(SearchTree_ElementType X, SearchTree T)
{
if (T == NULL)
return NULL;
else if (X < T->Element)
SearchTree_Find(X, T->Left);
else if (X > T->Element)
SearchTree_Find(X, T->Right);
else
return T;
}
(3)FindMax和Min
//FindMax和FindMin
SearchTree_Position SearchTree_FindMax(SearchTree T)
{
if (T == NULL)
return NULL;
else if (T->Right == NULL)
return T;
else
SearchTree_FindMax(T->Right);
} SearchTree_Position SearchTree_FindMin(SearchTree T)
{
if (T == NULL)
return NULL;
else if (T->Left == NULL)
return T;
else
SearchTree_FindMax(T->Left);
}
(4)插入
如果有重复单元进行插入,那可以选择加入一个count,记录加入多少次,而不用重复进行操作
//插入
SearchTree_Position SearchTree_Insert(SearchTree T,SearchTree_ElementType X)
{
if (T == NULL)
{
T = new SearchTreeNode;
if (T == NULL)
{
cout << "Out of Space" << endl;
}
else
{
T->Element = X;
T->Left = T->Right = NULL;
}
}
else if (T->Element > X)
SearchTree_Insert(T->Right, X);
else if (T->Element < X)
SearchTree_Insert(T->Left, X); return T;
}
(5)删除
删除的情况有3种:
a、没有儿子的,直接删除
b、有一个儿子的,删除这个节点之后,把子节点接上去
d、有两个儿子的,可以用右子树的最小值或者左子树的最大值代替该节点的数据并递归删除那个节点。
如果删除的次数有限,那么可以使用一个tag进行记录即可,即可以使用策略称为惰性测量。
//删除
SearchTree_Position SearchTree_Delete(SearchTree T, SearchTree_ElementType X)
{
SearchTree_Position NodeTemp; if (T == NULL)
cout << "Not Found" << endl;
else if (T->Element > X)
SearchTree_Delete(T->Left, X);
else if (T->Element < X)
SearchTree_Delete(T->Right, X);
else
{
if (T->Left && T->Right) //两个儿子
{
NodeTemp = SearchTree_FindMin(T->Right);
T->Element = NodeTemp->Element;
SearchTree_Delete(T->Right, T->Element);
}
else
{
NodeTemp = T;
if (T->Left == NULL)
T = T->Right;
else if (T->Right == NULL)
T = T->Left; delete NodeTemp;
}
} return T;
}
(二)——AVL树
1、AVL树定义:
每个节点的左子树和右子树的高度最多差1的二叉查找树(空树的高度定义为 -1)
2、旋转:
如果删除使用惰性删除,那么可能破坏AVL树的基本操作就只能是——插入。所以采用一种操作称为旋转来对树进行简单修正。
(1)AVL不平衡情况分析
假设必须平衡的点成为Node_A,那么有四种情况,(a d镜像 b c镜像)
a、对Node_A的左儿子的左子树进行一次插入
b、对Node_A的左儿子的右子树进行一次插入
c、对Node_A的右儿子的左子树进行一次插入
d、对Node_A的右儿子的右子树进行一次插入
对于a,d使用单旋转进行修正,对于b,c使用双旋转进行修正。
(2)单旋转
A、图示效果

其中左图所示的是情况a,X和Z的高度差2,所以要进行修正,有图是通过单旋转进行的修正。
方法:就是将K1拉起来,K2成为K1的右子树,Y成为K2的左子树。
B、参考代码
/**********************声明,类型定义**********************/
struct Avl_Node;
typedef struct AvlNode* Position;
typedef struct AvlNode* AvlTree; typedef int Avl_ElementType; /***********************函数声明**********************/ #define Max(a,b) (a>b?a:b) //单旋转
Position Avl_SingleRotateWithLeft(Position K2);
Position Avl_SingleRotateWithRight(Position K1); /***********************AVL数据结构定义**********************/
struct AvlNode
{
Avl_ElementType Element;
AvlTree Left;
AvlTree Right;
int Height;
};
这个是ADT的数据格式声明
//单旋转
Position Avl_SingleRotateWithLeft(Position K2)
{
Position K1; K1 = K2->Left;
K2->Left = K1->Right;
K1->Right = K2; K2->Height = Max(Avl_Get_NodeHeight(K2->Left), Avl_Get_NodeHeight(K2->Right)) + 1; K1->Height = Max(Avl_Get_NodeHeight(K1->Left), K2->Height) + 1; return K1;
}
Position Avl_SingleRotateWithRight(Position K1)
{
Position K2; K2 = K1->Right;
K1->Right = K2->Left;
K2->Left = K1; K1->Height = Max(Avl_Get_NodeHeight(K1->Left), Avl_Get_NodeHeight(K1->Right))+1;
K2->Height = Max(Avl_Get_NodeHeight(K2->Right), K1->Height) + 1; return K2;
}
(3)双旋转
A、图示效果

其中左图就是情况b,BC和D的高度差2,所以要修正,但是通过单旋转并没有办法进行修正,所以使用双旋转进行修正
方法:将K3成为根节点,K1,K2成为K3的子节点,B成为K1的右子树,C成为K2的左子树。
B、参考代码、
//双旋转
Position Avl_DoubleRotateWithLeft(Position K3)
{
K3->Left = Avl_SingleRotateWithRight(K3->Left); return Avl_SingleRotateWithLeft(K3);
}
Position Avl_DoubleRotateWithRight(Position K1)
{
K1->Right = Avl_SingleRotateWithLeft(K1->Right); return Avl_SingleRotateWithRight(K1);
}
3、AVL树的一些基本操作函数
#include "stdafx.h"
#include "AVL.h"
#include <iostream> using namespace std; //空树
AvlTree Avl_MakeEmpty(AvlTree T)
{
if (T != NULL)
{
Avl_MakeEmpty(T->Left);
Avl_MakeEmpty(T->Right);
free(T); }
return NULL;
} //查找
AvlTree Avl_Find(Avl_ElementType X, AvlTree T)
{
if (T == NULL)
{
return NULL;
cout << "Not Found!" << endl;
} if (X < T->Element)
{
return Avl_Find(X, T->Left);
}
else if (X > T->Element)
{
return Avl_Find(X, T->Right);
}
else
{
return T;
} } //查找极值
AvlTree Avl_FindMin(AvlTree T)
{
if (T == NULL)
{
return NULL;
}
else if (T->Right == NULL)
{
return T;
}
else
{
Avl_FindMin(T->Right);
}
} AvlTree Avl_FindMax(AvlTree T)
{
if (T == NULL)
{
return NULL;
}
else if (T->Left == NULL)
{
return T;
}
else
{
Avl_FindMin(T->Left);
}
} //获取树的高度,计算使用递归的方法
int Avl_Get_NodeHeight(Position P)
{
if (P == NULL)
return -1;
else
return P->Height;
} //单旋转
Position Avl_SingleRotateWithLeft(Position K2)
{
Position K1; K1 = K2->Left;
K2->Left = K1->Right;
K1->Right = K2; K2->Height = Max(Avl_Get_NodeHeight(K2->Left), Avl_Get_NodeHeight(K2->Right)) + 1; K1->Height = Max(Avl_Get_NodeHeight(K1->Left), K2->Height) + 1; return K1;
}
Position Avl_SingleRotateWithRight(Position K1)
{
Position K2; K2 = K1->Right;
K1->Right = K2->Left;
K2->Left = K1; K1->Height = Max(Avl_Get_NodeHeight(K1->Left), Avl_Get_NodeHeight(K1->Right))+1;
K2->Height = Max(Avl_Get_NodeHeight(K2->Right), K1->Height) + 1; return K2;
} //双旋转
Position Avl_DoubleRotateWithLeft(Position K3)
{
K3->Left = Avl_SingleRotateWithRight(K3->Left); return Avl_SingleRotateWithLeft(K3);
}
Position Avl_DoubleRotateWithRight(Position K1)
{
K1->Right = Avl_SingleRotateWithLeft(K1->Right); return Avl_SingleRotateWithRight(K1);
} //插入
AvlTree Avl_Insert(Avl_ElementType X, AvlTree T)
{ //空树
if (T == NULL)
{
T = new struct AvlNode;
if (T == NULL)
{
cout << "out of Space" << endl;
}
else
{
T->Element = X;
T->Height = 0;
T->Left = T->Right = NULL;
}
}
//在左子树
else if (X < T->Element)
{
Avl_Insert(X, T->Left);
if (Avl_Get_NodeHeight(T->Left) - Avl_Get_NodeHeight(T->Right) == 2)
{
if (X < T->Left->Element) //a情况
T = Avl_SingleRotateWithLeft(T);
else //b情况
T = Avl_DoubleRotateWithLeft(T);
}
}
else if (X>T->Element)
{
Avl_Insert(X, T->Right);
if (Avl_Get_NodeHeight(T->Right) - Avl_Get_NodeHeight(T->Left) == 2)
{
if (X < T->Right->Element) //c情况
T = Avl_DoubleRotateWithRight(T);
else //d情况
T = Avl_SingleRotateWithRight(T);
}
} T->Height = Max(Avl_Get_NodeHeight(T->Left), Avl_Get_NodeHeight(T->Right)) + 1;
return T;
}
(三)——树的遍历
1、三种遍历:先序、中序、后序
void PrintTree(SearchTree T)
{
if( T!= NULL)
{
PrintTree(T->Left);
PrintElement(T->Elemment);
PrintTree(T->Right);
}
}
《数据结构与算法分析》学习笔记(五)——二叉树的更多相关文章
- (转)Qt Model/View 学习笔记 (五)——View 类
Qt Model/View 学习笔记 (五) View 类 概念 在model/view架构中,view从model中获得数据项然后显示给用户.数据显示的方式不必与model提供的表示方式相同,可以与 ...
- <数据结构与算法分析>读书笔记--利用Java5泛型实现泛型构件
一.简单的泛型类和接口 当指定一个泛型类时,类的声明则包括一个或多个类型参数,这些参数被放入在类名后面的一对尖括号内. 示例一: package cn.generic.example; public ...
- C#可扩展编程之MEF学习笔记(五):MEF高级进阶
好久没有写博客了,今天抽空继续写MEF系列的文章.有园友提出这种系列的文章要做个目录,看起来方便,所以就抽空做了一个,放到每篇文章的最后. 前面四篇讲了MEF的基础知识,学完了前四篇,MEF中比较常用 ...
- java之jvm学习笔记五(实践写自己的类装载器)
java之jvm学习笔记五(实践写自己的类装载器) 课程源码:http://download.csdn.net/detail/yfqnihao/4866501 前面第三和第四节我们一直在强调一句话,类 ...
- Learning ROS for Robotics Programming Second Edition学习笔记(五) indigo computer vision
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 Learning ROS for Robotics Pr ...
- Typescript 学习笔记五:类
中文网:https://www.tslang.cn/ 官网:http://www.typescriptlang.org/ 目录: Typescript 学习笔记一:介绍.安装.编译 Typescrip ...
- <数据结构与算法分析>读书笔记--最大子序列和问题的求解
现在我们将要叙述四个算法来求解早先提出的最大子序列和问题. 第一个算法,它只是穷举式地尝试所有的可能.for循环中的循环变量反映了Java中数组从0开始而不是从1开始这样一个事实.还有,本算法并不计算 ...
- <数据结构与算法分析>读书笔记--运行时间计算
有几种方法估计一个程序的运行时间.前面的表是凭经验得到的(可以参考:<数据结构与算法分析>读书笔记--要分析的问题) 如果认为两个程序花费大致相同的时间,要确定哪个程序更快的最好方法很可能 ...
- ES6学习笔记<五> Module的操作——import、export、as
import export 这两个家伙对应的就是es6自己的 module功能. 我们之前写的Javascript一直都没有模块化的体系,无法将一个庞大的js工程拆分成一个个功能相对独立但相互依赖的小 ...
- <数据结构与算法分析>读书笔记--函数对象
关于函数对象,百度百科对它是这样定义的: 重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象.又称仿函数. 听起来确实很难懂,通过搜索我找到一篇 ...
随机推荐
- Apache2.4.6 添加虚拟主机
apache2.4 与 apache2.2 的虚拟主机配置写法有所不同 apache2.2的写法: <VirtualHost *:80> ServerName domain.com Doc ...
- CMake入门以及学习笔记
使用cef3替代chromium内核开发产品过程中,第一次接触到系统构建,使用了最常见的CMake.CMake虽然在构建系统中用的比较多,但是使用到的程序员还是很少的.现在在国内能找到的相关资料和博客 ...
- ePass1000 Full ActiveX Control Reference Manual Version 2.0
ePass1000 Full ActiveX Control Reference Manual Version 2.0 Error Code Value Return Status Descripti ...
- UrlEncoder url编码
public static string PercentEncode(string s) { var bytes = Encoding.UTF8.GetBytes( ...
- code vs1262 不要把球传我(组合数学) 2012年CCC加拿大高中生信息学奥赛
1262 不要把球传我 2012年CCC加拿大高中生信息学奥赛 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 题解 查看运行结果 题目描述 De ...
- Hadoop 分布式文件系统:架构和设计
引言 Hadoop分布式文件系统(HDFS)被设计成适合运行在通用硬件(commodity hardware)上的分布式文件系统.它和现有的分布式文件系统有很多共同点.但同时,它和其他的分布式文件系统 ...
- LeetCode 409 Longest Palindrome
Problem: Given a string which consists of lowercase or uppercase letters, find the length of the lon ...
- 获取http请求响应头
一直都是在给服务器端发送请求的时候可能会出现设置头文件的情况,但这次获取HTTP 返回的头文件,着实让我纠结一番,但最终还是实现了,总结一下.(PS:其实最后方法很简单,只是分享一下纠结过程) 先看一 ...
- Python简易聊天工具-基于异步Socket通信
继续学习Python中,最近看书<Python基础教程>中的虚拟茶话会项目,觉得很有意思,自己敲了一遍,受益匪浅,同时记录一下. 主要用到异步socket服务客户端和服务器模块asynco ...
- [Android Pro] linux下查看一个文件的属性(ls,lsattr,file,stat)
reference to : http://blog.chinaunix.net/uid-28458801-id-4615294.html 查看文件属性有多种方法,且这些方法中偏向不同,具体如下: 1 ...