• 树遍历算法概述


    树的遍历

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

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

    实例:

    • 先序遍历: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

  • 相关阅读:
    Python之正则表达式(re模块)
    正则表达式总结
    Python之日志处理(logging模块)
    Python之向日志输出中添加上下文信息
    python之配置日志的几种方式
    OSG3.4内置Examples解析【目录】
    探究osg中的程序设计模式【目录】
    3wwang的2019计划
    《探索未知种族之osg类生物》目录
    探索未知种族之osg类生物---渲染遍历之裁剪三
  • 原文地址:https://www.cnblogs.com/duanxz/p/2733804.html
Copyright © 2020-2023  润新知