前序遍历是中左右,如果还有左子树就一直向下找。完了之后再返回从最底层逐步向上向右找。 不难写出如下代码: (注意代码中,空节点不入栈)
public List<Integer> preOrderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) {
return res;
}
Deque<TreeNode> stack = new LinkedList<TreeNode>();
TreeNode node = root;
while (!stack.isEmpty() || node != null) {
while (node != null) {
res.add(node.val);
stack.push(node);
node = node.left;
}
node = stack.pop();
node = node.right;
}
return res;
}
class Solution:
def preorderTraversal(self, root):
res = list()
if not root:
return res
stack = []
node = root
while stack or node:
while node:
res.append(node.val)
stack.append(node)
node = node.left
node = stack.pop()
node = node.right
return res
此时会发现貌似使用迭代法写出前序遍历并不复杂,我们继续看中序遍历:
再看中序遍历,中序遍历是左中右,先访问的是二叉树左子树的节点,然后一层一层向下访问,直到到达树左面的最底部,再开始处理节点(也就是在把节点的数值放进res列表中)。在使用迭代法写中序遍历,就需要借用指针的遍历来帮助访问节点,栈则用来处理节点上的元素。 看代码:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
Deque<TreeNode> stack = new LinkedList<TreeNode>();
while(!stack.isEmpty() || root!= null){
while(root != null){
stack.push(root);
root = root.left;
}
root = stack.pop();
res.add(root.val);
root = root.right;
}
return res;
}
}
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> stk;
while (root != nullptr || !stk.empty()) {
while (root != nullptr) {
stk.push(root);
root = root->left;
}
root = stk.top();
stk.pop();
res.push_back(root->val);
root = root->right;
}
return res;
}
};
def inorderTraversal(self,root):
if not root:
return []
res = []
stack = []
while stack or root:
while root:
stack.append(root)
root = root.left
node = stack.pop()
res.append(node.val)
root = node.right
return res
后序遍历的非递归实现有三种基本的思路:反转法、访问标记法、和Morris法,可惜三种理解起来都有些难度,如果头发不够,可以等一等再学习。
个人感觉访问标记法是最难理解的方法,而Morris法是一个老外发明的巧妙思想:不使用栈,而是用好树中的null指针,但是实现后序仍然非常麻烦,我们这里不再展开,感兴趣的同学可以查一下,
我们这里只介绍一种好理解又好实现的方法:反转法。
如下图,我们先观察后序遍历的结果是seq={9 5 7 4 3},如果我们将其整体反转的话就是new_seq={3 4 7 5 9}。
你有没有发现要得到new_seq的方法和前序遍历思路几乎一致,只不过是左右反了。前序是先中间,再左边然后右边,而这里是先中间,再后边然后左边。那我们完全可以改造一下前序遍历,得到序列new_seq之后再reverse一下就是想要的结果了,代码如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if(root == null){
return res;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode node = root;
while(!stack.isEmpty() || node != null){
while(node != null){
res.add(node.val);
stack.push(node);
node = node.right;
}
node = stack.pop();
node = node.left;
}
Collections.reverse(res);
return res;
}
}
def postorderTraversal(self, root):
res = []
if root is None:
return res
stack = []
node = root
while stack or node:
while node:
res.append(node.val)
stack.append(node)
node = node.right
node = stack.pop()
node = node.left
res.reverse()
return res
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if (root == nullptr) {
return res;
}
stack<TreeNode*> stack;
TreeNode* node = root;
while (!stack.empty() || node != nullptr) {
while (node != nullptr) {
res.push_back(node->val);
stack.push(node);
node = node->right;
}
node = stack.top();
stack.pop();
node = node->left;
}
reverse(res.begin(), res.end());
return res;
}
};
阅读量:676
点赞量:0
收藏量:0