一、非递归先序遍历:先遍历根节点,后左,再右。先访问即任一节点,其可看作是根节点,因此可以直接访问;访问之后,若其左孩子不为空,按相同的规则访问他的左子树。
当访问其左子树,再访问其右子树,处理过程如下:
1、访问节点cur,将其入栈;
2、判断节点cur的左孩子是否为空,若为空,则取栈顶节点出栈,并将其右孩子置为当前访问节点。
3、若不为空,则循环将其左孩子置为当前节点。
注意:访问结点的位置要在循环中,先访问。
1 void PreOrder(TreeNode* root,vector<int>& res) 2 { 3 stack<TreeNode*> s; 4 TreeNode* cur=root; 5 while (!s.empty() || cur) 6 { 7 while (cur) 8 { 9 res.push_back(cur->val); 10 s.push(cur); 11 cur = cur->left; 12 } 13 if (!s.empty()) 14 { 15 cur = s.top(); 16 s.pop(); 17 cur = cur->right; 18 } 19 } 20 21 }
2、非递归中序遍历:根据中序遍历的要求,优先访问其左孩子,而左孩子节点又可以看作是一根节点,然后继续访问其左孩子,直到遇到左孩子节点为空才进行访问,然后按相同规则访问右子树。
对于节点cur ,若其左孩子不为空,则将cur入栈,并将其左孩子置为当前cur.然后当前cur做出相同处理。
若其左孩子为空,则取栈顶元素并进行出栈,访问该栈顶元素,然后将当前cur的右孩子置为cur.
注意:主要是访问节点的时机同先序不同
void InOrder(TreeNode* root,vector<int>& res) { stack<TreeNode*> s; TreeNode* cur=root; while (!s.empty() || cur) { while (cur) { s.push(cur); cur = cur->left; } if (!s.empty()) { cur = s.top(); res.push_back(cur->val);//先访问左孩子。不是在入栈过程中访问了 s.pop(); cur = cur->right; } } }
3、非递归后序遍历:后序遍历中要保证左孩子和右孩子都已经被访问过并且左孩子在右孩子之前访问才能访问根节点。
要保证根节点在左右子树访问之后才能访问因此对于任意节点cur,先将其入栈。
1、如果cur不存在左孩子和右孩子则直接访问。
2、如果cur存在左孩子或者右孩子,但是左孩子或右孩子都已经被访问过了。
同样可以访问该节点,所以可以引入一个pre节点,存储前一次访问的节点。
如果不是上面的两种情况,则将cur的右孩子入栈
再将cur的左孩子入栈(一定要现将右孩子入栈)
1 void PostOrder(TreeNode* root,vector<int>& res) 2 { 3 stack<TreeNode*> s; 4 TreeNode* cur; 5 TreeNode* pre = NULL; 6 if (!root) return; 7 s.push(root); 8 while (!s.empty()) 9 { 10 cur = s.top(); 11 if (!cur->left&&!cur->right||(pre!==NULL&&(pre==cur->left||pre==cur->right))) 12 { 13 res.push_back(cur->val); 14 s.pop(); 15 pre = cur; 16 } 17 else 18 { 19 if (cur->right) s.push(cur->right); 20 if (cur->left) s.push(cur->left); 21 } 22 } 23 24 }