转自:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/leetcodesuan-fa-xiu-lian-dong-hua-yan-shi-xbian-2/
1.递归解法
前中后遍历都很简单,就不写了。
2.迭代解法
力扣144题,二叉树的前序遍历:前序遍历的迭代解法,也是比较简单,利用栈先入根节点,根节点弹出,再入右子节点和左子节点,那么之后就是左子节点先弹出进行遍历,右子节点们一直被压栈。
class Solution { public: vector<int> preorderTraversal(TreeNode* root) { vector<int> ans; if(!root) return ans; stack<TreeNode*> st; st.push(root); while(!st.empty()){ TreeNode* t=st.top();st.pop(); ans.push_back(t->val); if(t->right)st.push(t->right); if(t->left)st.push(t->left); } return ans; } };
力扣94题,二叉树的中序遍历:
Java版本的代码:
public static void inOrderIteration(TreeNode head) { if (head == null) { return; } TreeNode cur = head; Stack<TreeNode> stack = new Stack<>(); while (!stack.isEmpty() || cur != null) { while (cur != null) { stack.push(cur); cur = cur.left; } TreeNode node = stack.pop(); System.out.print(node.value + " "); if (node.right != null) { cur = node.right; } } } 作者:gre-z 链接:https://leetcode-cn.com/problems/binary-tree-preorder-traversal/solution/leetcodesuan-fa-xiu-lian-dong-hua-yan-shi-xbian-2/ 来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
内部的while循环表示处理左子树,然后node就是当前的节点,也就相当于此子树中的根节点,然后right了就是去遍历右子树了。
3月份的时候学习过,当然过了7个月到现在已经全忘记了。。。
力扣145题,二叉树的后序遍历:可以通过对前序遍历的栈来实现,后序遍历也用栈存储,前序中根先入遍历的时候弹出,左右入,弹出就是根右左的顺序了。
class Solution { public: vector<int> postorderTraversal(TreeNode* root) { vector<int> ans; if(!root) return ans; stack<TreeNode*> pre,post; pre.push(root); while(!pre.empty()){ TreeNode* top=pre.top();pre.pop(); post.push(top); if(top->left)pre.push(top->left); if(top->right)pre.push(top->right); } while(!post.empty()){ ans.push_back(post.top()->val); post.pop(); } return ans; } };
第二种解法:
class Solution { public: vector<int> postorderTraversal(TreeNode* root) { vector<int> ans; if(!root) return ans; TreeNode* head=root;//指向的是访问的前一个节点 stack<TreeNode*> st; st.push(root); while(!st.empty()){ TreeNode* top=st.top(); if(top->left!=NULL && top->left !=head && top->right!=head){ st.push(top->left); }else if(top->right!=NULL && top->right != head){//左为空或者左已被访问过。 st.push(top->right); }else{//如果左右子节点均为空,或者都已被访问过,那么就将当前ans ans.push_back(top->val); st.pop();//出栈的并且进入ans后才表示它被访问过,而且是下一个被访问的前一个节点,以此标注 head=top; } } return ans; } };
https://www.cnblogs.com/grandyang/p/4251757.html,讲的很好。
3.Morris解法
https://www.cnblogs.com/anniekim/archive/2013/06/15/morristraversal.html,经典教程。
二叉树的遍历和搜索时间复杂度是不一样的,前着一定是O(n),后者最优是O(logn),退化为链表的是O(n)。
上面链接中给出了两段代码,我觉得关键还是要知道自己遍历一下,对两种不同的情况,print节点的时候意味着什么。这个搞清楚才可以。
我终于知道这个意味着什么了!
99题恢复二叉搜索树,也用到了这个解法:
//中序遍历: void inorderMorrisTraversal(TreeNode *root) { TreeNode *cur = root, *prev = NULL; while (cur != NULL) { if (cur->left == NULL) // 1. {//当左子树为空时,那么中序遍历就可以打印cur节点 printf("%d ", cur->val); cur = cur->right; } else { // find predecessor prev = cur->left; while (prev->right != NULL && prev->right != cur) prev = prev->right; if (prev->right == NULL) // 2.a) {//这里表示去遍历左子树了。 prev->right = cur; cur = cur->left; } else // 2.b) {//到这一步就意味着,左子树遍历完了,接下来要去遍历右子树了,所以可以打印当前节点(中序遍历) prev->right = NULL; printf("%d ", cur->val); cur = cur->right; } } } }
下面是先序遍历:
void preorderMorrisTraversal(TreeNode *root) { TreeNode *cur = root, *prev = NULL; while (cur != NULL) { if (cur->left == NULL) { printf("%d ", cur->val);//如果左子树为空,那么可以打印当前 cur = cur->right; } else { prev = cur->left; while (prev->right != NULL && prev->right != cur) prev = prev->right; if (prev->right == NULL) {//这里将要去遍历左子树,因为是先根所以先打印一下cur节点 printf("%d ", cur->val); // the only difference with inorder-traversal prev->right = cur; cur = cur->left; } else {//这里表示左子树和当前cur遍历完了,去遍历右子树 prev->right = NULL; cur = cur->right; } } } }
//至于morris后根,我还没看,代码好长啊