二叉树遍历归纳
前序遍历的方法
方法一
1.根节点入栈
2.在List中添加根节点
3.判断右左孩子是否为空,若为空,则入栈
4.一定要先右后左的入栈,这样才能保证出栈时是先左后右
5.放在while中循环,实现类似递归
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> list = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
if(root!=null){
stack.push(root);
}
while (!stack.empty()){
TreeNode top = stack.pop();
list.add(top.val);
if(top.right!=null){
stack.push(top.right);
}
if(top.left!=null){
stack.push(top.left);
}
}
return list;
}
方法二
1.将当前节点及其不为null的左孩子全部放入栈中
2.每次循环将根节点放入List中,随后将根节点改变为根的左孩子
3.若左孩子为空,自动跳出内while循环,进入if,弹出栈顶元素,并将根节点改变为栈顶元素的右孩子,继续执行1.2操作,当节点为null,且栈为空时结束
如图
class Solution {
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<>();
Stack<TreeNode> stack = new Stack<>();
while(root!=null || !stack.isEmpty()){
while(root!=null){
stack.push(root);
result.add(root.val);
root = root.left;
}
if(!Stack.empty()){
root = stack.pop().right;
}
}
return result;
}
}
方法三(递归)
1.首先遍历顺序采用根左右的顺序进行
2.上图顺序为递归顺序,较好理解
class Solution {
List<Integer> list = new ArrayList<>();
public List<Integer> preorderTraversal(TreeNode root) {
helper(root);
return list;
}
public void helper(TreeNode root){
if(root == null){
return;
}
list.add(root.val);
helper(root.left);
helper(root.right);
}
}
中序遍历算法
方法一
1.将根节点压栈,将根节点变为其左孩子,且进行压栈
2.若其左孩子为空则将此时栈顶元素出栈,并将值加入List
3.将根变为栈顶元素的右孩子重复执行其步骤至结束
public List<Integer> inorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null)
return res;
Stack<TreeNode> stack = new Stack<>();
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
if (!stack.isEmpty()) {
root = stack.pop();
res.add(root.val);
root = root.right;
}
}
return res;
}
方法二(递归)
与前序及后序方式类似,看代码
public void inOrderTraversal(TreeNode node) {
if (node == null)
return;
inOrderTraversal(node.left);
System.out.println(node.val);
inOrderTraversal(node.right);
}
后序遍历算法
方法一
前序:根-左-右
后序:左-右-根
后序相当于 [根-右-左] 的逆序。
对于迭代求前序遍历可以根节点先入栈,然后右子树进栈,最后左子树进栈;
此时便可以根节点先入栈,然后左子树进栈,最后右子树进栈,最后将列表逆序即为所求。
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
Stack<TreeNode> stack = new Stack<>();
List<Integer> res = new ArrayList<Integer>();
if(root == null){
return res;
}
if(root != null){
stack.push(root);
}
while(!stack.empty()){
TreeNode top = stack.pop();
res.add(top.val);
if(root.left != null){
stack.push(top.left);
}
if(root.right != null){
stack.push(top.right);
}
}
return res;
}
}
方法二(迭代)
1.根节点进栈
2.根左节点进栈
3.若此时的左节点无孩子则prev标记此处,并出栈加入List
4.继续将栈中的数出栈,若有孩子则放回栈内且将其孩子压栈
5.重复此过程至所有节点遍历完且栈为空
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) {
return res;
}
Deque<TreeNode> stack = new LinkedList<TreeNode>();
TreeNode prev = null;
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
if (root.right == null || root.right == prev) {
res.add(root.val);
prev = root;
root = null;
} else {
stack.push(root);
root = root.right;
}
}
return res;
}
}
方法三(递归)
按照访问左子树——右子树——根节点的方式遍历这棵树,而在访问左子树或者右子树的时候,我们按照同样的方式遍历,直到遍历完整棵树。因此整个遍历过程天然具有递归的性质,我们可以直接用递归函数来模拟这一过程。
定义 postorder(root) 表示当前遍历到 root 节点的答案。按照定义,我们只要递归调用 postorder(root->left) 来遍历 root 节点的左子树,然后递归调用 postorder(root->right) 来遍历 root 节点的右子树,最后将 root 节点的值加入答案即可,递归终止的条件为碰到空节点。
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
postorder(root, res);
return res;
}
public void postorder(TreeNode root, List<Integer> res) {
if (root == null) {
return;
}
postorder(root.left, res);
postorder(root.right, res);
res.add(root.val);
}
}
递归方式一般都相对简单,但迭代法较难理解,尤其借助栈实现容易搞混
多画图多理解
借助动画演示
仔细理解过程
多练习!!!!