树遍历算法概述

树的遍历

遍历定义——指按某条搜索路线遍访每个结点且不重复(又称周游)
遍历用途——它是树结构插入、删除、修改、查找和排序运算的前提,是二叉树一切运算的基础和核心
遍历方法——牢记一种约定,对每个结点的查看都是“先左后右”

树的遍历有两个基本的方法:深度优先遍历 和 广度优先遍历
深度优先遍历又根据处理节点的顺序不同,可以分为:中序遍历、前序遍历和后序遍历。这些知识点也是深度优先遍历经常考察的。
广度优先遍历的考察在于层次遍历

实例:

  • 先序遍历:ABCDEFGH
  • 中序遍历:BDCEAFHG
  • 后序遍历:DECBHGFA

树遍历的口诀

  • DLR—先序遍历,即先根再左再右
  • LDR—中序遍历,即先左再根再右
  • LRD—后序遍历,即先左再右再根

简单讲就是根节点先、中、后的顺序。

树的递归遍历代码

    public class BiTree {
        String val;
        BiTree left;
        BiTree right;

        BiTree(String x) {
            val = x;
        }
    }

树的先序遍历

    public void preOrder(BiTree root) {
        if (root == null) {
            return;
        }
        System.out.print(root.val + " ");
        preOrder(root.left);
        preOrder(root.right);
    }

树的中序遍历

    public void inOrder(BiTree root) {
        if (root == null) {
            return;
        }
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }

 树的后序遍历

    public void postOrder(BiTree root) {
        if (root == null) {
            return;
        }
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.val + " ");
    }

 

测试:

    /**
     * A
     * / \
     * B   F
     * /     \
     * C       G
     * / \     /
     * D   E   H
     */
    @Test
    public void testOrder() {
        BiTree tn = new BiTree("A");
        tn.left = new BiTree("B");
        tn.left.right = new BiTree("C");
        tn.left.right.left = new BiTree("D");
        tn.left.right.right = new BiTree("E");
        tn.right = new BiTree("F");
        tn.right.right = new BiTree("G");
        tn.right.right.left = new BiTree("H");
        System.out.print("递归前序遍历:");
        preOrder(tn);
        System.out.println();
        System.out.print("递归中序遍历:");
        inOrder(tn);
        System.out.println();
        System.out.print("递归后序遍历:");
        postOrder(tn);
        System.out.println();
        System.out.print("非递归前序遍历:");
        preOrderTraversal(tn);
        System.out.println();
        System.out.print("非递归中序遍历:");
        midOrderTraversal(tn);
        System.out.println();
        System.out.print("非递归后序遍历:");
        postOrderTraversal(tn);
        System.out.println();
        System.out.print("非递归广度遍历:");
        levelOrderTraversal(tn);
        System.out.println();
    }

 递归遍历思想

从前面的三种遍历算法可以知道:如果将print语句抹去,从递归的角度看,这三种算法是完全相同的,或者说这三种遍历算法的访问路径是相同的,只是访问结点的时机不同
从虚线的出发点到终点的路径上,每个结点经过3次
第1次经过时访问=先序遍历
第2次经过时访问=中序遍历
第3次经过时访问=后序遍历

二叉树遍历的时间效率和空间效率
时间效率:O(n) //每个结点只访问一次
空间效率:O(n) //栈占用的最大辅助空间(精确值:树深为k的递归遍历需要k+1个辅助单元!)

树的非递归遍历

1、广度优先遍历-层次遍历

优先遍历-层次遍历实现的方式,使用了队列的FIFO的方式,将所有暂未访问的节点存入一个队列结构,先进根节点,然后循环:出队列头,然后分别进左,右子树节点。如此反复,直至队列为空。
如下代码是经典的广度遍历
    /**
     * 广度优先遍历,非递归实现,需要辅助数据结构:队列
     * @param root
     */
    public void levelOrderTraversal(BiTree root) {
        if (root == null) {
            System.out.println("empty tree");
            return;
        }
        ArrayDeque<BiTree> queue = new ArrayDeque<BiTree>();
        queue.add(root);
        while (queue.isEmpty() == false) {
            BiTree node = queue.remove();
            System.out.print(node.val + " ");
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }
        System.out.print("\n");
    }

 

结果:A B F C G D E H

2、树非递归的先序遍历

算法思想:

    /**
     * 非递归-前序遍历
     *
     * @param root
     */
    public void preOrderTraversal(BiTree root) {
        if (root == null) return;
        Stack<BiTree> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            BiTree node = stack.pop();
            System.out.print(node.val + " ");
            if (node.right != null) {
                stack.push(node.right);
            }
            if (node.left != null) {
                stack.push(node.left);
            }
        }
    }

 

中序遍历:

    /**
     * 非递归-中序
     *
     * @param root
     */
    public void midOrderTraversal(BiTree root) {
        if (root == null) return;
        Stack<BiTree> stack = new Stack<>();
        while (root != null || !stack.isEmpty()) {
            if (root != null) {
                stack.push(root);
                root = root.left;
            } else {
                BiTree node = stack.pop();
                System.out.print(node.val + " ");
                root = node.right;
            }
        }
    }

 

后序遍历:

    /**
     * 非递归-后序
     * @param root
     */
    public void postOrderTraversal(BiTree root) {
        if (root == null) return;
        Stack<BiTree> stack1 = new Stack<>();
        Stack<BiTree> stack2 = new Stack<>();
        stack1.push(root);
        while (!stack1.isEmpty()) {
            root = stack1.pop();
            stack2.push(root);
            if (root.left != null) {
                stack1.push(root.left);
            }
            if (root.right != null) {
                stack1.push(root.right);
            }
        }

        while (!stack2.isEmpty()) {
            System.out.print(stack2.pop().val + " ");
        }
    }

 

结果:

递归前序遍历:A B C D E F G H 

递归中序遍历:B D C E A F H G 

递归后序遍历:D E C B H G F A 

非递归前序遍历:A B C D E F G H 

非递归中序遍历:B D C E A F H G 

非递归后序遍历:D E C B H G F A 

非递归广度遍历:A B F C G D E H 

 

 

全部代码:

import org.junit.Test;

import java.util.ArrayDeque;
import java.util.Stack;

public class Tree {
    public class BiTree {
        String val;
        BiTree left;
        BiTree right;

        BiTree(String x) {
            val = x;
        }
    }

    public void preOrder(BiTree root) {
        if (root == null) {
            return;
        }
        System.out.print(root.val + " ");
        preOrder(root.left);
        preOrder(root.right);
    }

    public void inOrder(BiTree root) {
        if (root == null) {
            return;
        }
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    }

    public void postOrder(BiTree root) {
        if (root == null) {
            return;
        }
        postOrder(root.left);
        postOrder(root.right);
        System.out.print(root.val + " ");
    }

    /**
     * A
     * / \
     * B   F
     * /     \
     * C       G
     * / \     /
     * D   E   H
     */
    @Test
    public void testOrder() {
        BiTree tn = new BiTree("A");
        tn.left = new BiTree("B");
        tn.left.right = new BiTree("C");
        tn.left.right.left = new BiTree("D");
        tn.left.right.right = new BiTree("E");
        tn.right = new BiTree("F");
        tn.right.right = new BiTree("G");
        tn.right.right.left = new BiTree("H");
        System.out.print("递归前序遍历:");
        preOrder(tn);
        System.out.println();
        System.out.print("递归中序遍历:");
        inOrder(tn);
        System.out.println();
        System.out.print("递归后序遍历:");
        postOrder(tn);
        System.out.println();
        System.out.print("非递归前序遍历:");
        preOrderTraversal(tn);
        System.out.println();
        System.out.print("非递归中序遍历:");
        midOrderTraversal(tn);
        System.out.println();
        System.out.print("非递归后序遍历:");
        postOrderTraversal(tn);
        System.out.println();
        System.out.print("非递归广度遍历:");
        levelOrderTraversal(tn);
        System.out.println();
    }

    /**
     * 非递归-前序遍历
     *
     * @param root
     */
    public void preOrderTraversal(BiTree root) {
        if (root == null) return;
        Stack<BiTree> stack = new Stack<>();
        stack.push(root);
        while (!stack.isEmpty()) {
            BiTree node = stack.pop();
            System.out.print(node.val + " ");
            if (node.right != null) {
                stack.push(node.right);
            }
            if (node.left != null) {
                stack.push(node.left);
            }
        }
    }

    /**
     * 非递归-中序
     *
     * @param root
     */
    public void midOrderTraversal(BiTree root) {
        if (root == null) return;
        Stack<BiTree> stack = new Stack<>();
        while (root != null || !stack.isEmpty()) {
            if (root != null) {
                stack.push(root);
                root = root.left;
            } else {
                BiTree node = stack.pop();
                System.out.print(node.val + " ");
                root = node.right;
            }
        }
    }

    /**
     * 非递归-后序
     * @param root
     */
    public void postOrderTraversal(BiTree root) {
        if (root == null) return;
        Stack<BiTree> stack1 = new Stack<>();
        Stack<BiTree> stack2 = new Stack<>();
        stack1.push(root);
        while (!stack1.isEmpty()) {
            root = stack1.pop();
            stack2.push(root);
            if (root.left != null) {
                stack1.push(root.left);
            }
            if (root.right != null) {
                stack1.push(root.right);
            }
        }

        while (!stack2.isEmpty()) {
            System.out.print(stack2.pop().val + " ");
        }
    }

    /**
     * 广度优先遍历,非递归实现,需要辅助数据结构:队列
     *
     * @param root
     */
    public void levelOrderTraversal(BiTree root) {
        if (root == null) {
            System.out.println("empty tree");
            return;
        }
        ArrayDeque<BiTree> queue = new ArrayDeque<BiTree>();
        queue.add(root);
        while (queue.isEmpty() == false) {
            BiTree node = queue.remove();
            System.out.print(node.val + " ");
            if (node.left != null) {
                queue.add(node.left);
            }
            if (node.right != null) {
                queue.add(node.right);
            }
        }
        System.out.print("\n");
    }
}
View Code

 

 参考:https://blog.csdn.net/Erice_s/article/details/78375302?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_utm_term~default-0.pc_relevant_paycolumn_v3&spm=1001.2101.3001.4242.1&utm_relevant_index=3

posted on 2012-10-22 13:55  duanxz  阅读(557)  评论(0编辑  收藏  举报