二叉树遍历

重建二叉树

对着背影说爱祢 提交于 2020-01-28 05:07:09
题目:重建二叉树 题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。 思路 前序遍历:中左右 中序遍历:左中右 根据pre[0]=vin[i]找出根(mid)的位置,递归左右子树 #include<iostream> #include<vector> #include<queue> #include<stack> using namespace std; struct TreeNode{ int val; TreeNode *left; TreeNode *right; TreeNode(int x): val(x), left(NULL), right(NULL){ } }; class Solution{ public: // 思路:递归左右子树,找出左右的pre和vin TreeNode *reConstructBinaryTree(vector<int> pre, vector<int> vin){ int mid, size=pre.size(); if(size==0) return NULL; TreeNode *root = new TreeNode(pre[0]); //

二叉树遍历 递归非递归

霸气de小男生 提交于 2020-01-27 22:06:12
二叉树是一种非常重要的数据结构,很多其它数据结构都是基于二叉树的基础演变而来的。对于二叉树,有前序、中序以及后序三种遍历方法。因为树的定义本身就是递归定义,因此采用递归的方法去实现树的三种遍历不仅容易理解而且代码很简洁。而对于树的遍历若采用非递归的方法,就要采用栈去模拟实现。在三种遍历中,前序和中序遍历的非递归算法都很容易实现,非递归后序遍历实现起来相对来说要难一点。 一.前序遍历 前序遍历按照“根结点-左孩子-右孩子”的顺序进行访问。 1.递归实现 void preOrder1(BinTree *root) //递归前序遍历 { if(root!=NULL) { cout<<root->data<<" "; preOrder1(root->lchild); preOrder1(root->rchild); }} 2.非递归实现 根据前序遍历访问的顺序,优先访问根结点,然后再分别访问左孩子和右孩子。即对于任一结点,其可看做是根结点,因此可以直接访问,访问完之后,若其左孩子不为空,按相同规则访问它的左子树;当访问其左子树时,再访问它的右子树。因此其处理过程如下: 对于任一结点P: 1)访问结点P,并将结点P入栈; 2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P; 3

二叉树遍历(递归、非递归)

喜你入骨 提交于 2020-01-27 04:51:59
1、递归遍历 1 void helper(TreeNode* root, vector<int>& res) { 2 if (root) { 3 res.push_back(root->val); 4 helper(root->left, res); 5 helper(root->right, res); 6 } 7 } 把3~5行按照访问顺序交换一下位置,就能实现前序遍历、中序遍历和后序遍历。 2、非递归遍历 非递归遍历可以用栈实现。 a. 前序遍历(144. Binary Tree Preorder Traversal) 前序遍历节点访问次序是 根-左-右 所以对于弹出的每一个节点,进栈顺序是先右孩子,再左孩子 1 class Solution { 2 public: 3 vector<int> preorderTraversal(TreeNode* root) { 4 vector<int> res; 5 stack<TreeNode*> stk; 6 if(root) 7 stk.push(root); 8 while (!stk.empty()) { 9 TreeNode *temp = stk.top(); 10 stk.pop(); 11 res.push_back(temp->val); 12 if (temp->right) 13 stk.push(temp-

二叉树遍历基础 -- 递归与非递归的实现方法

 ̄綄美尐妖づ 提交于 2020-01-25 06:19:57
之前也写过不少关于二叉树的东西了,但是总体来说,二叉树还是一个很绕的东西,所以单独择出来写一篇笔记,之前也没计划什么的,就想到什么写什么吧。不过该篇文章的 主要内容是关于二叉树的三种遍历(前序、中序、后序)不同的实现方式(递归与非递归) 。 首先,我觉得很有必要去彻底理解一下递归。 (1)递归的主体大概分两部分:递归停止的条件、递归内容。 (2)递归应用的实例:这个超级多,就比如最典型的 斐波那契数列 。个人认为,可以用循环实现的,递归基本上都可以实现,但有时递归的效率不如循环。 (3)递归又分为单递归与多递归(二叉树的三种遍历递归方法均用到了双递归!) 根据上面的三点,举个例子先。 假设当x=0时,F(x)=1;否则F(x)=F(n-1)*n。这个时候就可以用递归了,代码实现如下。 class Solution{ public int F(int n) { //递归停止条件 if (n == 0) { return 1; } //递归内容 else { return F(n - 1) * n; } } } 代码分析一下如下: 二叉树的三种遍历:前序(根左右)、中序(左根右)、后序(左右根) 首先看 三种遍历的递归实现方法 。(特点:代码清晰,量少,但不易理解) // (1)前序遍历 public TreeNode PreOrder(TreeNode pRoot) { /

前、中、后序遍历二叉树

喜你入骨 提交于 2020-01-25 01:11:19
后序遍历 后序遍历首先遍历左子树,然后遍历右子树,最后访问根结点,在遍历左、右子树时,仍然先遍历左子树,然后遍历右子树,最后遍历根结点。即: 若 二叉树 为空则结束返回, 否则: (1)后序遍历左子树 (2)后序遍历右子树 (3)访问根结点 如右图所示 二叉树 后序遍历结果:DEBFCA 中序遍历 中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。若 二叉树 为空则结束返回,否则: (1)中序遍历左子树 (2)访问根结点 (3)中序遍历右子树 如右图所示二叉树,中序遍历结果:DBEAFC 前序遍历 前序遍历首先访问根结点然后遍历左子树,最后遍历右子树。在遍历左、右子树时,仍然先访问 根结点 ,然后遍历左子树,最后遍历右子树。 若 二叉树 为空则结束返回,否则: (1)访问根结点。 (2)前序遍历左子树 。 (3)前序遍历右子树 。 前序遍历 需要注意的是:遍历左右子树时仍然采用前序遍历方法。 如右图所示 二叉树 前序遍历结果:ABDECF 已知后序遍历和中序遍历,就能确定前序遍历。 来源: CSDN 作者: 这瓜保熟么 链接: https://blog.csdn.net/luzhensmart/article/details/104062758

算法 :重建二叉树

廉价感情. 提交于 2020-01-24 23:30:39
** 题目: 输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字 ** public static TreeNode construct(int[] preorder,int[] inorder){ if(preorder == null || inorder == null){ return null; } return constructCore(preorder,0,preorder.length-1,inorder,0,inorder.length-1); } private static TreeNode constructCore(int[] preorder, int startPre, int endPre, int[] inorder, int startIn, int endIn) { if(startPre < endPre || startIn < endIn){ return null; } TreeNode root = new TreeNode(startPre); for(int i = startIn ; i < endIn ; i++){ if(preorder[startPre] == inorder[i]){ //找到之后,分别对左子树和右子树进行递归算法,重复此步骤 root

Morris 遍历

心已入冬 提交于 2020-01-24 06:54:31
1. 二叉树遍历 树是最重要的数据结构之一,而树的遍历是树最基本的操作。 二叉树的遍历一般来说有三种遍历次序: 前序遍历 中序遍历 后序遍历 而这三种遍历次序都可以采用 递归 和 非递归 的方式来完成。 就时间、空间的复杂度来讲,因为非递归需要借助额外的 Stack 来完成操作,所以递归和非递归的时间复杂度都是 O(n) , O(logn) 。 那么有没有另外的不同的二叉树遍历方法,在时间或空间能做到更优的呢?答案是: Morris 遍历 。 由于在遍历的时候,我们需要记住某种遍历次序的的 后驱 或者 前驱 结点,常见的递归和非递归都是采用 栈 的方式完成这个过程,有没有内部空间来记录这些后驱或者前驱结点呢?有,那就是叶结点的左,右孩子结点,因为叶结点的两个孩子结点都是空指针,如果利用好这些空间,我们就可以在 O(1) 的空间完成遍历。 利用叶结点的左、右孩子指向遍历的前驱或者后驱结点,这些指针叫做 线索 ,对应的二叉树叫做 线索二叉树 。 Morris遍历 是使用线索二叉树进行中序遍历的一种实现 ,其可以在 O(n) 的时间, O(1) 的空间完成遍历, 对其稍加修改可以推广到 先序、后序遍历 ,其遍历过程包含三个部分: 创建指向 中序后驱 结点的线索; 遍历输出结点; 删除线索,恢复树的结构; 2. Morris 中序遍历 Morris 中序遍历过程如下:

Morris遍历遍历二叉树

孤街浪徒 提交于 2020-01-22 22:51:29
遍历二叉树的递归方法使用了函数栈,非递归方法使用了申请的栈, 两者的额外空间都与树的高度有关,所以空间复杂度为O(h),h为二叉树的高度。 可以使用二叉树叶子节点中大量指向null的指针实现空间复杂度O(1)的遍历。 Morris遍历的实质就是避免使用栈结构,让下层到上层有指针, 具 体是通过让底层节点指向null的空闲指针指回上层的某个节点,从而完成下层到上层的移动。 先序中序后序主要基于两个主要步骤,然后输出的位置有所不同,以中序遍历为例。 中序遍历: 1、假设当前子树的头节点为h,让h的左子树中最右节点的right指针指向h, 然后h的左子树继续步骤1的处理过程,直到遇到某一个节点没有左子树时记为node,进入步骤2。 2、从node开始通过每个节点的right指针进行移动并以此打印,假设移动到的节点为cur。 对每一个cur节点都判断cur节点的左子树中最右节点是否指向cur。 Ⅰ 如果是,令cur节点的左子树中最右节点的right指针指向null,即恢复树的本来面貌, 然后打印cur,继续通过cur的right指针移动到下一个节点。重复步骤2。 Ⅱ 如果不是,以cur为头的子树重回步骤1执行。 public void morrisIn(TreeNode root) { if (root == null) return; TreeNode cur1 = root;

根据前序遍历和中序遍历的结果重构二叉树LeetCode 95

只愿长相守 提交于 2020-01-22 05:25:16
题目描述 https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ 根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3 / \ 9 20 / \ 15 7 思路 首先我们在上一篇文章中解释了前序遍历和中序遍历的含义,因为是树的结构,一般都是用递归来实现。 用数学归纳法的思想就是,假设最后一步,就是root的左右子树都已经重建好了,那么我只要考虑将root的左右子树安上去即可。 根据前序遍历的性质,第一个元素必然就是root,那么下面的工作就是如何确定root的左右子树的范围。 根据中序遍历的性质,root元素前面都是root的左子树,后面都是root的右子树。那么我们只要找到中序遍历中root的位置,就可以确定好左右子树的范围。 简单来说就是当前前序遍历的结果,第一个元素必然是当前节点的值,而对于中序遍历来说,当前节点值的位置的前面都是左子树的值,后面都是右子树的值,所以根据这个思想,重新构建二叉树。 实现代码 /** * Definition for a binary tree

二叉树遍历,递归,栈,Morris

只愿长相守 提交于 2020-01-21 08:09:44
一篇质量非常高的关于二叉树遍历的帖子,转帖自http://noalgo.info/832.html 二叉树遍历(递归、非递归、Morris遍历) 2015年01月06日 | 分类: 数据结构 | 标签: 二叉树遍历 | 评论: 8条评论 | 浏览:6,603次 二叉树遍历是二叉树中最基本的问题,其实现的方法非常多,有简单粗暴但容易爆栈的递归算法,还有稍微高级的使用栈模拟递归的非递归算法,另外还有不用栈而且只需要常数空间和线性时间的神奇Morris遍历算法,本文将对这些算法进行讲解和实现。 递归算法 二叉树节点使用以下数据结构进行表示,包括关键字、左儿子、右儿子属性和一个带默认参数的构造函数。 struct成员的默认属性为public,于是可以直接访问。 struct Node { int val; Node *left, *right; Node(int v = 0, Node *l = NULL, Node *r = NULL) : val(v), left(l), right(r) {} }; 二叉树的递归算法非常简单,设置好递归出口之后,根据遍历的顺序,对当前节点的左右子递归调用自身即可。其前序、中序、后序遍历的代码如下。 void preorder1(Node *root) //递归前序遍历 { if (root == NULL) return; printf("%d ",