潍坊市论坛

注册

 

发新话题 回复该主题

为实习准备的数据结构4二叉树 [复制链接]

1#
彭洋挂号 https://baijiahao.baidu.com/s?id=1705314659791057393&wfr=spider&for=pc&searchword=%E5%BD%AD%E6%B4%8B%E6%8C%82%E5%8F%B7
前言

半年前,种过一次树,有不少朋友喜欢。但是接下来我又要重新种树了,因为我发现,有瑕疵(我忘得差不多了)。不过可以放心,前面那篇我不会删,毕竟大家比较喜欢。

能不多说话就不多说话,需要看概念的话可以去前一篇:种树[1]

二叉树二叉树的创建

classTreeNode{private:intval;//这里的数据类型按需取TreeNode*left;TreeNode*right;publicreeNode(intx):val(x),left(NULL),right(NULL){}intget_val(){returnthis-val;}TreeNode*getleft(){returnthis-left;}TreeNode*getright(){returnthis-right;}voidset_left(TreeNode*node){this-left=node;}voidset_right(TreeNode*node){this-right=node;}};二叉树的前序遍历

以此图为例:==先访问根结点,然后再访问左子树,最后访问右子树。==

voidPreOrderTraverse(TreeNode*root){if(NULL==root){return;}coutroot-get_val()endl;PreOrderTraverse(root-getleft());PreOrderTraverse(root-getright());}

打印信息:ABDECFG

二叉树的中序遍历

==先访问左子树,中间访问根节点,最后访问右子树。==

voidMidOrderTraverse(TreeNode*root){if(NULL==root){return;}MidOrderTraverse(root-getleft());coutroot-get_val()endl;MidOrderTraverse(root-getright());}

打印信息:DBEAFCG

二叉树的后序遍历

==先访问左子树,再访问右子树,最后访问根节点。==

voidLastOrderTraverse(TreeNode*root){if(NULL==root)return;LastOrderTraverse(root-left);LastOrderTraverse(root-right);coutroot-val;}

打印顺序:DEBFCA

已知前、中序遍历,还原二叉树

==特别标注:如果二叉树中有相同值元素的存在,那么有极大概率还原失败,下面中、后序遍历也是==

给了中序那就好办了一:看中序排列中的根节点位置在哪里,根节点前面都属于根的左子树及其后代,后面你懂得。二:将中序序列分两段:(D、B、E)和(F、C、G)三:明眼人一看就知道根节点左子树的“根节点”是:B别问我为啥,问就是看前序序列的第二位四:重复二三,直到根节点左子树排出来为止五:同上,排出右子树

具体思路:

对于任意一颗树而言,前序遍历的形式总是[根节点,[左子树的前序遍历结果],[右子树的前序遍历结果]]即根节点总是前序遍历中的第一个节点。

而中序遍历的形式总是[[左子树的中序遍历结果],根节点,[右子树的中序遍历结果]]

只要我们在中序遍历中定位到根节点,那么我们就可以分别知道左子树和右子树中的节点数目。由于同一颗子树的前序遍历和中序遍历的长度显然是相同的,因此我们就可以对应到前序遍历的结果中,对上述形式中的所有左右括号进行定位。

这样以来,我们就知道了左子树的前序遍历和中序遍历结果,以及右子树的前序遍历和中序遍历结果,我们就可以递归地对构造出左子树和右子树,再将这两颗子树接到根节点的左右位置。

细节

在中序遍历中对根节点进行定位时,一种简单的方法是直接扫描整个中序遍历的结果并找出根节点,但这样做的时间复杂度较高。我们可以考虑使用哈希映射(HashMap)来帮助我们快速地定位根节点。对于哈希映射中的每个键值对,键表示一个元素(节点的值),值表示其在中序遍历中的出现位置。在构造二叉树的过程之前,我们可以对中序遍历的列表进行一遍扫描,就可以构造出这个哈希映射。在此后构造二叉树的过程中,我们就只需要O(1)的时间对根节点进行定位了。

下面的代码给出了详细的注释。

classSolution{private:unordered_mapint,intindex;publicreeNode*myBuildTree(constvectorintpreorder,constvectorintinorder,intpreorder_left,intpreorder_right,intinorder_left,intinorder_right){if(preorder_leftpreorder_right){returnnullptr;}//前序遍历中的第一个节点就是根节点intpreorder_root=preorder_left;//在中序遍历中定位根节点intinorder_root=index[preorder[preorder_root]];//先把根节点建立出来TreeNode*root=newTreeNode(preorder[preorder_root]);//得到左子树中的节点数目intsize_left_subtree=inorder_root-inorder_left;//递归地构造左子树,并连接到根节点//先序遍历中「从左边界+1开始的size_left_subtree」个元素就对应了中序遍历中「从左边界开始到根节点定位-1」的元素root-left=myBuildTree(preorder,inorder,preorder_left+1,preorder_left+size_left_subtree,inorder_left,inorder_root-1);//递归地构造右子树,并连接到根节点//先序遍历中「从左边界+1+左子树节点数目开始到右边界」的元素就对应了中序遍历中「从根节点定位+1到右边界」的元素root-right=myBuildTree(preorder,inorder,preorder_left+size_left_subtree+1,preorder_right,inorder_root+1,inorder_right);returnroot;}TreeNode*buildTree(vectorintpreorder,vectorintinorder){intn=preorder.size();//构造哈希映射,帮助我们快速定位根节点for(inti=0;in;++i){index[inorder]=i;}returnmyBuildTree(preorder,inorder,0,n-1,0,n-1);}};作者:LeetCode-Solution链接:

分享 转发
TOP
发新话题 回复该主题