数据结构与算法基础 模块三
在昨天的分享中,主要是说明了相关树的内容,那么紧接着上一次的内容,来说一下查找二叉树的相关基本操作,在查找二叉树中,重要分为三种操作:
1、查找 :
①首先需要判断key是否为根节点
②与当前的值进行比较,若小,进入左子树,反之,进入右子树。
③重复以上操作,直到找到
2、插入结点
在查找二叉树中插入一个结点需要分以下几种情况,然后再分别进行相应的处理:
① 如果相同链值的结点已经在查找二叉树中,则不再插入。
② 如果查找二叉树为空树,则以新结点为查找二叉树
③ 将要插入的结点的键值与插入后的父结点的键值比较,就能确定结点是父结点的左子结点还是右子结点,并进行相应的插入。
3、删除结点
再删除结点的时候,需要考虑三种情况:
① 若待删除的结点p是叶子结点,则直接删除该结点
② 若待删除的结点p只有一个节点,则将这个子结点与待删除的父节点值直接连接,然后删除结点P
③若待删除的节点p有两个结点,则在其左子树上,用中序遍历寻找关键值最大的结点s,用结点s的值代替结点p的值,然后删除结点s,结点s必属于上述已经说明的①②情况。
例:
利用逐点插入法建立序列(50,72,43,85,75,20,35,45,65,30)对应的二叉排列树以后,查找元素30所需要进行几次元素间的比较?
答: 五次比较
解析:首先,在我们做这个题目之前,需要回想一下我们在上一个模块的最后与大家分享的知识点,二叉排序树的创建方法。首先,我们需要确定一个点为根节点,在这个题目中,显而易见,根节点为50,那么现在要比较接下来各数之间的大小,小于根节点的为左子树,大于根节点的为右子树。那么现在我们先建立一颗二叉排序树。
建立完成之后,再根据基本操作中查找操作,一步一步进行查询,比较大小,这里有一个诀窍,就是直接用30与跟结点比较,若大,在右反之在左,这样会缩小我们查找的范围,提高效率。最后需要注意的一点是,有的人最后算下来的结果会是4次,是因为少了一次,就是30它和它自己本身的一次比较。
最优二叉树(哈夫曼树)
同样的,我们来看一下有关哈夫曼树的关键词:
1.树的路径长度:在同样结点的树中,完全二叉树的路长最短
2、权:权这个概念是人为定的。
3、带权路径长度:权*本身的键值
最后我们需要知道的是 ,哈夫曼树是带权路长最小的树 (路长:路径长度)
那么,在知道相关的内容之后,我们就要考虑如何构造一颗哈夫曼树,直观点,我们用一道例题来说明一下:
例:
假设有一组权值(5,29,7,8,14,23,3,11),下面我们将利用这组权值来构造哈夫曼树
解析:
第一步:以这八个权值作为根节点的权值构造具有8颗树的森林;
第二步:从中选择两个根的权值作为最小的树,3.5作为左右子树来构造一颗新树,并将这两颗树从森林中删除,并将新树添加进去。
第三步:重复第二步,直到森林中只有一颗树为止。
需要注意的是,我们要知道,这八个权值,分别作为一颗空树,不能说是一颗树有了左右结点之后,他就不作为前面所做的空树。
线索二叉树
在我们之前讲了呢么多的树时候,又有一种新的概念,线索二叉树,首先我们需要明确一下,为什么要有线索二叉树:
简单来说,线索二叉树就是用来记录二叉树按某种遍历之后所产生的前驱后继关系。也就是说利用现有的空间(空结点)来存储信息。
普通二叉树的结点存储结构是: 左指针域 data域 右指针域
线索二叉树的结点存储结构是: 左标志域 左指针域 data域 右指针域 右标志域
在刚开始,线索二叉树是为了节省空间,用现有的结点来存储信息的,但Lbit 域和Rbit域是否会占用存储空间,这个时候,我们需要明白的是,在左右标志域都为逻辑上的字段,非常省空间,只需要一个位就可以了。
对于标志域的要求如下:
Lbit=0,Lchild 是通常的指针
Lbit=1,Lchild是线索
Rbit=0,Rchild是通常的指针
Rbit=1,Rchild是线索
那么,我们如何将二叉树转换为线索二叉树呢?
这个问题比较复杂并且也是比较重要的一部分知识点。
所以,为了明了起见,用一道例题能够更好的说明, 用一颗二叉树,将其前序,中序,后序的线索树画出来。
因为软件原因,无法很好地将其构造树的过程表现出来,所以现在将他的过程文字表达出来。
首先,按照正常的流程,将二叉树的前序,中序和后序表现出来,之后,我们可以很明了的看出来,在前序的遍历当中,每一个的前驱和后继,记住,只需要看找出来的前序中,分别前去和后记,不用再去管原来在二叉树上的关系。之后,再根据自己画出来了前序,中序,后序中的前驱后继关系在原来的二叉树上表现出来就可以了。