144. Binary Tree Preorder Traversal
2016-07-24 11:44
260 查看
题目:二叉树前序遍历
Given a binary tree, return the preorder traversal of its nodes' values.
For example:
Given binary tree
return
Note: Recursive solution is trivial, could you do it iteratively?
题意:
给定一个二叉树,返回其节点值的前序遍历序列。
Note:
递归实现是微不足道的,你能否用迭代实现。
思路一:
最简单的递归实现,只需要按照前序遍历流程递归调用递归函数即可。
代码:C++版:3ms
思路二:
利用栈辅助实现二叉树的先序遍历。先将根节点入栈,在循环体中,取出栈顶节点,将该节点值保存进返回结果集中,之后依次将右节点,左节点入栈,利用栈的先入后出的特点实现先序遍历的顺序。之后执行循环体即可。
代码:C++版:0ms
思路三:
使用Morris遍历实现。其时间复杂度仍然是O(n),但是空间复杂度却只有O(1)。
其优点概括来说有两个:1. O(1)空间复杂度,即只能使用常数空间;2. 二叉树的形状不会被破坏(中间过程允许改变其形状)。
要使用O(1)空间进行遍历,最大的难点在于,遍历到子节点的时候怎样重新返回到父节点(假设节点中没有指向父节点的p指针),由于不能用栈作为辅助空间。为了解决这个问题,Morris方法用到了线索二叉树(threaded binary tree)的概念。在Morris方法中不需要为每个节点额外分配指针指向其前驱(predecessor)和后继节点(successor),只需要利用叶子节点中的左右空指针指向某种顺序遍历下的前驱节点或后继节点就可以了。
它使用二叉树中的叶节点的right指针来保存后面将要访问的节点的信息,当这个right指针使用完成之后,再将它置为NULL,但是在访问过程中有些节点会访问两次,所以与递归的空间换时间的思路不同,Morris则是使用时间换空间的思想。
参考图示流程更容易看懂:
![](http://img.blog.csdn.net/20141006185342265?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbXh3OTc2MjM1OTU1/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
代码:C++版:0ms
详细算法流程参考博客:Morris二叉树遍历算法
Given a binary tree, return the preorder traversal of its nodes' values.
For example:
Given binary tree
{1,#,2,3},
1 \ 2 / 3
return
[1,2,3].
Note: Recursive solution is trivial, could you do it iteratively?
题意:
给定一个二叉树,返回其节点值的前序遍历序列。
Note:
递归实现是微不足道的,你能否用迭代实现。
思路一:
最简单的递归实现,只需要按照前序遍历流程递归调用递归函数即可。
代码:C++版:3ms
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { private: vector<int> ans; public: vector<int> preorderTraversal(TreeNode* root) { repreTra(root); return ans; } void repreTra(TreeNode *root) { if (root != NULL) { ans.push_back(root->val); //前序遍历root->left->right repreTra(root->left); repreTra(root->right); } } };
思路二:
利用栈辅助实现二叉树的先序遍历。先将根节点入栈,在循环体中,取出栈顶节点,将该节点值保存进返回结果集中,之后依次将右节点,左节点入栈,利用栈的先入后出的特点实现先序遍历的顺序。之后执行循环体即可。
代码:C++版:0ms
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { private: vector<int> ans; public: vector<int> preorderTraversal(TreeNode* root) { vector<int> res; //返回结果集 const TreeNode *p; //取出每次出栈的节点 stack<const TreeNode*> stk; //辅助栈 p = root; if (p != nullptr) stk.push(p); //将根节点入栈 while (!stk.empty()) { p = stk.top(); stk.pop(); res.push_back(p->val); //将出栈节点值存储到返回集中 if (p->right != nullptr) stk.push(p->right); //右节点先入栈,因为栈先进后出的特点 if (p->left != nullptr) stk.push(p->left); //左节点入栈 } return res; } };
思路三:
使用Morris遍历实现。其时间复杂度仍然是O(n),但是空间复杂度却只有O(1)。
其优点概括来说有两个:1. O(1)空间复杂度,即只能使用常数空间;2. 二叉树的形状不会被破坏(中间过程允许改变其形状)。
要使用O(1)空间进行遍历,最大的难点在于,遍历到子节点的时候怎样重新返回到父节点(假设节点中没有指向父节点的p指针),由于不能用栈作为辅助空间。为了解决这个问题,Morris方法用到了线索二叉树(threaded binary tree)的概念。在Morris方法中不需要为每个节点额外分配指针指向其前驱(predecessor)和后继节点(successor),只需要利用叶子节点中的左右空指针指向某种顺序遍历下的前驱节点或后继节点就可以了。
它使用二叉树中的叶节点的right指针来保存后面将要访问的节点的信息,当这个right指针使用完成之后,再将它置为NULL,但是在访问过程中有些节点会访问两次,所以与递归的空间换时间的思路不同,Morris则是使用时间换空间的思想。
参考图示流程更容易看懂:
代码:C++版:0ms
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { private: vector<int> ans; public: vector<int> preorderTraversal(TreeNode* root) { vector<int> res; TreeNode *cur; cur = root; while (cur != nullptr) { if (cur->left == nullptr) { res.push_back(cur->val); cur = cur->right; } else { //查找前驱 TreeNode *node = cur->left; while (node->right != nullptr && node->right != cur) //找到右子树的叶子节点 node = node->right; if (node->right == nullptr) { //还没线索化,则建立线索 res.push_back(cur->val); //仅这一行的位置与中序遍历不同 node->right = cur; cur = cur->left; } else { //已经线索化,则删除线索 node->right = nullptr; cur = cur->right; } } } return res; } }
详细算法流程参考博客:Morris二叉树遍历算法
相关文章推荐
- SDUT 2141 数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历
- JSP技术(二)——JSP指令
- PAT 1016 Mice and Rice (25)
- 超级表格创始人中学时代揭秘
- ubuntu中source insight打不开,报错pagefault的解决方法
- DOM
- 《浪潮之巅》观后感
- poj 1201 Intervals [差分约束]
- Python之Pycharm常用快捷键
- 7.22号布置的作业
- IO - 同步,异步,阻塞,非阻塞
- UDP协议点对点(P2P)通讯(或者说NAT穿越)实例
- 盒子模型简介
- ubuntu 上查看内存信息
- FHIR概述
- CodeForces 437C The Child and Toy
- 上海 交通卡退卡规则,余额给退吗
- 辗转相除求gcd
- Ubuntu从入门到精通 ubuntu如何设置和打开3D效果桌面
- 21. Merge Two Sorted Lists(Sort)