D&F学数据结构系列——二叉排序树

时间:2021-07-07 22:11:50

二叉排序树(Binary Sort Tree)

定义:对于树中的每个结点X,它的左子树中所有关键字值小于X的关键字值,而它的右子树中所有关键字值大于X的关键字值。

二叉查找树声明:

 #ifndef _Tree_H

 struct TreeNode;
typedef struct TreeNode *Position;
typedef struct TreeNode *SearchTree; SearchTree MakeEmpty(SearchTree T);
Position Find(ElementType X,SearchTree T);
Position FindMin(SearchTree T);
Position FindMax(SearchTree T);
SearchTree Insert(ElementType X,SearchTree T);
SearchTree Delete(ElementType X,SearchTree T);
ElementType Retrieve(Position P);
#endif /*_Tree_H*/

TreeNode结构体定义(二叉树的二叉链表存储表示法):

/*Place in the implementation file*/
struct TreeNode
{
ElementType Element;
SearchTree Left;
SearchTree right;
};

建立一棵空树:

 SearchTree MakeEmpty(SearchTree T)
{
if(T!=NULL)
{
MakeEmpty(T->Left);
MakeEmpty(T->right);
free(T);
}
return NULL;
}

Find操作:

 Position Find(ElementType X,SearchTree T)
{
if(T==NULL)
return NULL;
if(X<T->Element)
return Find(X,T->Left);
else if(X>T->Element)
return Find(X,T->Right);
else
return T;
}

FindMin的递归实现和FindMax的非递归实现:

 Position FindMin(SearchTree T)
{
if(T==NULL)
return NULL;
else if(T->Left==NULL)
return T;
else
return FindMin(T->Left);
} Position FindMax(SearchTree T)
{
if(T!=NULL)
while(T->Right!=NULL)
T=T->Right;
return T;
}

FindMax的非递归形式看不懂啊,求大神!T怎么可以被改变,改了之后怎么办,根节点都变了呀?整个树不就变了吗?

Inset操作:

 SearchTree Insert(ElementType X,SearchTree T)
{
if(T==NULL)
{
T=malloc(sizeof(struct TreeNode));
if(T==NULL)
FatalError("Out of space!!!");
else
{
T->Element=X;
T->Left=T->Right=NULL;
}
}
else if(X<T->Element)
T->Left=Insert(X,T->Left);
else if(X>T->Element)
T->Right=Insert(X,T->Right);
else ;
return T;
}

(1)由于T指向该树的根,而根又在第一次插入时变化,因此Insert被写成一个返回指向新树根的指针的函数

(2)第5行malloc函数,生成一个新节点,注意6、7行对新节点是否创建成功的检查

(3)14~17行,递归地插入X到适当位置,并建立新节点与父节点的联系

Delete操作:

删除操作是二叉排序树最困难的操作。仔细分析就会得出,删除操作仅仅包括以下三种情况:

情况一:如果要删除的结点X是一片树叶,没有子女。此时只需要直接将这个结点删除即可,不需要其它操作。

情况二:如果要删除的结点X只有一个子女。此时令X的子女直接成为X的双亲结点F的子树,然后删掉X即可。

情况三:如果要删除的结点X有两个子女。一般的策略是用X的右子树的最小结点(《算法导论》中称其为X的后继,若想了解后继这个概念,我的博文http://www.cnblogs.com/sage-blog/p/3865260.html),代替X并递归地删除那个结点。

 SearchTree Delete(ElementType X,SearchTree T)
{
Position TmpCell;
if(T==NULL)
Error("Elment not found!!!");
else if(X<T->Element) //向左寻找
T->Left=Delete(X,T->Left);
else if(X>T->Element) //向右寻找
T->Right=Delete(X,T->Right);
else if(T->Left&&T->Right) //找到结点,并且它有两个子女
{
TmpCell=FindMin(T-Right);
T->Element=TmpCell->Element;
T->Right=Delete(T->Element,T->Right);
}
else //找到结点,并且它只有一个子女或它没有子女
{
TmpCell=T;
if(T->Left==NULL)
T=T->Right;
else if(T->Right==NULL)
T=T->Left;
free(TmpCell);
}
return T;
}

时间复杂度分析:

(1)假设所有树出现的机会均等,则树的所有节点的平均深度为O(log N)

(2)在某种情况下,上面描述的算法有助于使得左子树比右子树深度深,因为我们总是用右子树的一个节点来代替删除的节点,造成树的不平衡。

存在的问题:

(1)如果向一棵树中输入预先排好序的数据(例如数据是递增的),那么一连串的Insert操作将花费二次时间,因为此时只由那些没有左儿子的结点组成。一种解决的办法就是要有一个称为平衡(balance)的附件的结构条件:任何节点的深度均不能过深。

实现树的平衡:平衡二叉树,也称之为AVL树(Adelson-Velskii和Landis),详见我的博客:http://www.cnblogs.com/sage-blog/p/3866008.html

(2)另外,较新的方法是放弃平衡条件,允许树有任意深度,但是在每次操作之后要使用一个调整规则进行调整,使得后面的操作效率更高。这种类型的数据一般属于自调整(self-adjusting)类结构。在二叉查找树的情况下,对于任意单个运算我们不再保证O(log N)的时间界,但是任意连续M次操作在最坏情况下花费时间为O(Mlog N)。

这种数据结构叫做伸展树(splay tree),详见我的博客:***

D&F学数据结构系列——二叉排序树的更多相关文章

  1. D&amp&semi;F学数据结构系列——B树(B-树和B&plus;树)介绍

    B树 定义:一棵B树T是具有如下性质的有根树: 1)每个节点X有以下域: a)n[x],当前存储在X节点中的关键字数, b)n[x]个关键字本身,以非降序存放,因此key1[x]<=key2[x ...

  2. D&amp&semi;F学数据结构系列——前驱和后继

    前驱和后继 本文所述为二叉排序树的前驱和后继,如果想了解二叉排序树的概念,可以参考我的博文http://www.cnblogs.com/sage-blog/p/3864640.html 给定一个二叉查 ...

  3. D&amp&semi;F学数据结构系列——二叉堆

    二叉堆(binary heap) 二叉堆数据结构是一种数组对象,它可以被视为一棵完全二叉树.同二叉查找树一样,堆也有两个性质,即结构性和堆序性.对于数组中任意位置i上的元素,其左儿子在位置2i上,右儿 ...

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

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

  5. D&amp&semi;F学数据结构系列——插入排序

    插入排序(insertion sort) 插入排序由P-1趟(pass)排序组成.对于P=1趟到P=N-1趟,插入排序保证从位置0到位置P-1上的元素为已排序状态.插入排序利用了这样的事实:位置0到位 ...

  6. D&amp&semi;F学数据结构系列——红黑树

    红黑树 定义:一棵二叉查找树如果满足下面的红黑性质,则为一棵红黑树: 1)每个结点不是红的就是黑的 2)根结点是黑的 3)每个叶结点是黑的 4)如果一个结点是红的,它的两个儿子都是黑的(即不可能有两个 ...

  7. 重学数据结构系列之——平衡树之SB Tree(Size Blanced Tree)

    学习来源:计蒜客 平衡树 1.定义 对于每一个结点.左右两个子树的高度差的绝对值不超过1,或者叫深度差不超过1 为什么会出现这样一种树呢? 假如我们依照1-n的顺序插入到二叉排序树中,那么二叉排序树就 ...

  8. 简学Python第二章&lowbar;&lowbar;巧学数据结构文件操作

    #cnblogs_post_body h2 { background: linear-gradient(to bottom, #18c0ff 0%,#0c7eff 100%); color: #fff ...

  9. 跟着鸟哥学Linux系列笔记2-第10章VIM学习

    跟着鸟哥学Linux系列笔记0-扫盲之概念 跟着鸟哥学Linux系列笔记0-如何解决问题 跟着鸟哥学Linux系列笔记1 常用的文本编辑器:Emacs, pico, nano, joe, vim VI ...

随机推荐

  1. 如何解决Maple的应用在数学中

    对任意数学和技术学科的研究员.教师和学生而言,Maple是一个必备的工具.通过Maple,教师将复杂数学问题注入生命,学生的精力集中在概念理解上而不是如何使用工具上,研究员可以开发更复杂的算法或模型. ...

  2. oracle中查询某张表都被哪些表参照了

    起因: 系统测试的时候发现如果某条记录已经被引用了,这个时候删除这条记录会引起数据不一致,系统会报错.比如警员信息,在考勤记录表里会引用警员ID,如果考勤记录表中已经存在这个警员ID了,这时从警员表中 ...

  3. 传智168期JavaEE就业班 day03-js

    * 课程回顾: * CSS * CSS的简介 * 层叠样式表. * CSS与HTML的结合(4种) * HTML的标签提供了属性 style="CSS的代码" * HTML提供了标 ...

  4. VS2012 内容存储区指定的位置无效或者您无权访错误

    ——解决由于移动过microsoft help viwer( msdn )数据目录,又误删除数据目录后,引发其不能启动问题 1.使用命令行下载microsoft help viwer( msdn )数 ...

  5. win7提示&OpenCurlyDoubleQuote;ipconfig不是内部或外部命令”

    进入windows环境变量设置->系统变量,找到path,添加C:\Windows\SysWOW64,或者c:\windows\system32

  6. CocoaPods 报错 &lbrack;&excl;&rsqb; The dependency &grave;JSONModel &lpar;~&gt&semi; 1&period;2&period;0&rpar;&grave; is not used in any concrete target&period;

    当用CocoaPods  pod install 时出现了下面的错误时: p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 11.0px Menlo; col ...

  7. poj1797 Heavy Transportation Dijkstra算法的简单应用

    题目链接:http://poj.org/problem?id=1797 题目就是求所有可达路径的其中的最小值边权的最大值 即对于每一条能够到达的路径,其必然有其最小的承载(其实也就是他们自身的最大的承 ...

  8. &lpar;工具类&rpar;double类型数据运算

    package com.flf.util;import java.math.BigDecimal;/** * double类型数据运算 * @author Yancy 2016-12-14 * */p ...

  9. 设计模式学习之访问者模式(Visitor,行为型模式)(21)

    参考:https://www.cnblogs.com/edisonchou/p/7247990.html 在患者就医时,医生会根据病情开具处方单,很多医院都会存在以下这个流程:划价人员拿到处方单之后根 ...

  10. ServletContextListener使用详解(监听Tomcat启动、关闭)

    在 Servlet API 中有一个 ServletContextListener 接口,它能够监听 ServletContext 对象的生命周期,实际上就是监听 Web 应用的生命周期. 当Serv ...