给定一个二叉树,返回它的 前序 遍历。
示例:
输入: [1,null,2,3] 1 \ 2 / 3 输出: [1,2,3]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
二叉树的前序遍历有递归和非递归两种做法。
在介绍这两种方法之前,我首先介绍下,二叉树如何建立
struct TreeNode { int val; TreeNode* left; TreeNode* right; TreeNode(int x):val(x),left(NULL),right(NULL) {} }; void createBiTree(TreeNode* &T) //&的意思是传进来节点指针的引用,目的是让传递进来的指针发生改变 { int c; cin >> c; if(-1 == c) //当遇到-1时,令树的根节点为NULL,从而结束该分支的递归 T = NULL; else { T = new TreeNode(0); T->val=c; createBiTree(T->left); createBiTree(T->right); } }
(1)递归
思路:用递归的方法,这里用vector作为返回值,需要注意的是,当vector很大时,因为这样存在创建临时对象并拷贝的过程,空间时间开销会很大。一般返回的是引用,但是不能返回临时对象的引用。这里在外面定义了vector,因为如果定义在内部,每次递归都会重新创建一个vector,不符合我们想要的结果。
vector<int> a; vector<int> preorderTraversal(TreeNode* root)
{ if(root) { a.push_back(root->val);//这里每次将本次循环的根节点值放入数组中 preorderTraversal(root->left); preorderTraversal(root->right); } return a; }
(2)非递归
思路:非递归的形式,也叫作迭代形式。在遍历根节点后还要回来,因此要基于栈(先进后出)来保存节点。
根据前序遍历访问的顺序,优先访问根结点,然后再分别访问左孩子和右孩子。即对于任一结点,其可看做是根结点,因此可以直接访问,访问完之后,若其左孩子不为空,按相同规则访问它的左子树;当访问其左子树时,再访问它的右子树。因此其处理过程如下:
对于任一结点P:
1)访问结点P,并将结点P入栈;
2)判断结点P的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点P,循环至1);若不为空,则将P的左孩子置为当前的结点P;
3)直到P为NULL并且栈为空,则遍历结束。
vector<int> preorderTraversal(TreeNode* root)//非递归实现 { stack<TreeNode*> s; TreeNode* p=root; vector<int> a; while(p!=NULL || !s.empty())//这里是||,只要P不为空,或者栈里有节点,就要继续 { while(p) { s.push(p); a.push_back(p->val); p=p->left; } if(!s.empty()) { p=s.top(); s.pop(); p=p->right; } } return a; }