算法导论--二叉树

来源:互联网 发布:mac spaces 编辑:程序博客网 时间:2024/05/17 23:27

搜索树这个数据结果支持很多动态的操作:搜索、最小值啦、最大值,插入和删除,当然也可以作为词典以及优先级队列。

啥是二叉搜索树

这里写图片描述

上图便是二叉搜索树,一个父节点最大分两个叉,并且左孩子子树的所有节点小于等于父节点,右孩子子树的所有节点大于等于父节点。

这样就可以通过访问根节点顺序的不同递归遍历这样的二叉搜索树,这就是我们所熟知的:前序遍历,中序遍历,后序遍历。
这里写图片描述
上图伪代码是中序遍历,其实中序遍历二叉搜索树,就是按从小到大的顺序输出了各个元素,时间复杂是O(n),为什么呢,走直觉啊,其实证明也不难啦,自己去看看书里面人家公式是怎么推得就明白了。

访问二叉搜索树

我们经常需要搜索一个二叉搜索树。比如找到树种的最小值、最大值什么的,这里介绍一下这些操作是怎么用O(h)的时间来进行这些操作的,其中h是树的高度。
搜索:
用一个key值去查找中这个key值得元素。给定一个根节点的指针和一个Key k, TREE-SEARCH返回key=k的节点,如果不存在,返回NULL。
这里写图片描述
很容易理解,这里不再解释了。下面给一个非递归的算法
这里写图片描述

求最小值:
这里写图片描述
就是一直访问左子树,直到空,访问最大值同理。

Successor 和 Predeccessor
给定一个节点,有时候我们需要找到它的Successor(其实就是比这个节点key值大的节点里的最小值),原话是这样的:If all keys are distinct, the successor of a node x is the node with the smallest key greater than x:key。以下的程序返回node x的successor,如果x在树中有最大的key,则返回NULL。
伪代码如下:
这里写图片描述
第1-2行:
如果x的右孩子不是空,则返回右子树的最小节点。
第3行:令y = x的父节点
第4-6行:不太好讲,跑个例子就明白了
这里时间复杂度是O(h),很好理解,不再证明。

插入和删除节点

有一个点比较重要:就是再插入节点或者删除节点之后,还要保持二叉搜索的树的性质。
插入元素的伪代码如下:
这里写图片描述
第1-2行:初始化操作,令x指向根节点,y为空。
第4-7行:这个过程保存了一个指针y来指向x的父节点。这个while循环导致两个指针x和y从根走到叶子节点,直到x变成nil(空)。
第8-13行:这是一个将z插入到制定位置的过程。首先设置z的父节点是y。如果y==nil,说明这棵树本来是一个空树,设置T.root = z.然后根据z的key值和y的key值大小的比较,来决定z应该是y的哪个孩子,左孩子还是右孩子。

删除节点z的策略有三种情况。
第一种情况:如果z没有孩子,我们直接修改它的父节点指向它的指针为空即可。
第二种情况:如果z只有一个孩子,将z的父节点指向它的指针指向z的孩子即可
第三种情况:如果z有两个孩子,我们找到z的successor y,y肯定是z的右子树。这时候z原来的右子树成为y的右子树,z的左子树变成y的左子树。

删除节点z需要两个参数为T和z。

  1. 如果z没有左孩子,我们将z替换成它的右孩子,无论它的右孩子是否为空。
  2. 如果z只有一个孩子,并且是左孩子,我们将z替换成它的左孩子
  3. 如果z有两个孩子,我们找到z的successor y,即是z的右子树种的一个元素并且没有左孩子。
  4. 如果y是z的右孩子,我们用y替换掉z,什么都不用管。
    下图a,b,c,d分别对应四种情况
    这里写图片描述

伪代码描述如下:首先先定义一个TRANSPLANT方法:
这里写图片描述
这个方法其实就是将v和u替换在树中的位置,然后将u丢弃了。
然后是删除节点的伪代码:
这里写图片描述