Tree数据结构
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tree数据结构相关的知识,希望对你有一定的参考价值。
参考技术A Binary Tree中每一个节点有两个子节点,区别于Binary Search Tree, Binary Tree子节点之间不存在大小顺序关系,首先来看几个简单的问题:采用post order来计算树的大小
接着看如何判断两棵树是否相同:
另一个简单的例子计算数的高度或者最高深度:
那么如何删除tree呢?
这里采用了postorder的方式进行树的删除.
对于树这个数据结构,通常有几个基本的遍历方式perorder, inorder, postorder和level order,下面我们将分别详细描述这几种遍历方式:
preorder traversal一般有三种方式:recursive, iterative和Morris method. 从最简单的resursive的方式讨论:
对于recursive的方式,注意判断root是否为空,从recursive转化为iterative,我们需要辅助新的stack空间来实现:
这里需要注意的是每一次有新的元素推入栈中,需要判断这个元素是否为空,另外左右子节点的顺序与recursive的方式相反。我们知道每一个recursive的函数都可以又一个iterative的方式表示,因此我们可以通过模拟resursive function call来实现preorder遍历。
这里我们利用更新root本身来实现遍历,以上解法需要O(lgN)的额外空间,Morris方法可以不需要额外空间,具体如下:
这里仍然通过更新root来遍历,Binary Tree遍历问题有一个关键点就是当指针走到底层以后如何返回的问题,之前的方法都是通过stack或者function stack来解决,Morris方法有一个地方特别的是如果左子节点不为空的情况下,寻找它的前驱节点然后link起来,这样就可以让下层的节点和上层节点联系起来,等到第二次遍历的时候再让这种联系断开通过prev->right = nullptr;
Recursive method:
Iterative method:
Morris tree traversal:
相比较于preorder traversal, inorder Morris方法只是在节点打印的顺序上有一个改变就是当unlink前驱节点的同时打印当前节点,而preorder traversal是在link前驱节点的时候打印当前节点。
postorder在几个遍历方法中是比较复杂,首先看一下recursive的方法:
然后再看recursive的方法:
仔细分析不难看出这里使用了两个指针来记录节点访问情况,在第一个if中prev节点是curr节点的parent node, 因此curr还没有被访问于是将curr的子节点推入栈中。第二种情况prev是curr的左子节点,因此需要讲其右子节点推入栈中。其他情况则可以打印curr节点,更新prev节点。 对于recursive方法可以改写为以下这种形式:
从以上可以看出来刚开始一路向左推入栈中,然后检查right node是否被访问过p->right == q,以此来选择是否打印curr.另外还有一种省事的方法,即将preorder的方法将结果输入到一个stack中,然后反向输出即可:
PostOrder Morris方法比较复杂,需要utility function来辅助:
PostOrder Morris Tree Traversal在几个地方与之前有很大不同,首先用了临时节点dump,它的左子节点为root,并且注意cur是从临时节点开始的。其他逻辑结构与之前两种遍历类似,不同的地方是需要一个子过程反向输出两个节点之间所有的节点。
接下来就是level order traversal,与之前遍历方法的最大变化就是使用queue来代替stack的作用:
再写一个recursive版本, 这里需要几个辅助函数,一个是确定树的高度,另一个打印制定高度的node, 这里的时间复杂度是O(n^2):
下面来看几个level order traversal 的变种题目, level order in a zigzag fashion ,如果采用recursive的方式可以在上面的解答中加入一个变量判断是否需要反向输出, 其时间复杂度与前面一致都是O(n^2), 具体过程如下:
除此之外,iterative的解法则需要额外的空间stack来储存,并且记录当前层和下一层的node个数以及当前层访问过的node个数:
仔细发现,这道题的构架可以用来进行一起关于level order这样的操作,也就是说通过记录当前层和下一层的node个数可以知道目前是否访问到当前所有的node,用来判断是否要进行更新。
下面是另外一种level order traversal的变种:find next right node of a given key in level order traversal
再看一个简单的例子, Sum of all the numbers that are formed from root to leaf paths. Each node has a digit from 1 to 9.
不难看出,这里使用了preorder的思想来计算所有node的之和。
以上是关于Tree数据结构的主要内容,如果未能解决你的问题,请参考以下文章
[数据结构]Binary_tree | Binary_search_tree | avl_tree
请教各位C语言大神,啥样的数据结构时间复杂度最低?Binary Search Tree, AVL Tree, 2-3 Tree, B-Tree等
MySQL数据库索引原理 | 索引数据结构 | B+Tree