【算法】通过递归和非递归实现树的前中后序以及广度优先搜索和深度优先搜索

简介: 【算法】通过递归和非递归实现树的前中后序以及广度优先搜索和深度优先搜索

基本概念

树是一个有n个有限节点组成一个具有层次关系的集合,每个节点有0个或者多个子节点,没有父节点的节点称为根节点,也就是说除了根节点以外每个节点都有父节点,并且有且只有一个。

树的种类比较多,有二叉树,红黑树,AVL树,B树,哈夫曼树,字典树等等。

同时,树有比较多的需要掌握的概念

结点的度:一个结点含有的子结点的个数称为该结点的度;

叶结点或终端结点:度为0的结点称为叶结点;

非终端结点或分支结点:度不为0的结点;

双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点;

孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点;

兄弟结点:具有相同父结点的结点互称为兄弟结点;

树的度:一棵树中,最大的结点的度称为树的度;

结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推;

树的高度或深度:树中结点的最大层次;

堂兄弟结点:双亲在同一层的结点互为堂兄弟;

结点的祖先:从根到该结点所经分支上的所有结点;

子孙:以某结点为根的子树中任一结点都称为该结点的子孙。

森林:由m(m>=0)棵互不相交的树的集合称为森林;

无序树:树中任意节点的子结点之间没有顺序关系,这种树称为无序树,也称为自由树;

有序树:树中任意节点的子结点之间有顺序关系,这种树称为有序树;

二叉树:每个节点最多含有两个子树的树称为二叉树;

完全二叉树:若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h

层所有的结点都连续集中在最左边,这就是完全二叉树

满二叉树:除最后一层无任何子节点外,每一层上的所有结点都有两个子结点的二叉树。

哈夫曼树:带权路径最短的二叉树称为哈夫曼树或最优二叉树;

定义一棵树

public class TreeNode {
    public int val;
     public TreeNode left;
     public TreeNode right;
     public TreeNode(int x) {
         val = x;
     }
    public TreeNode() {
}

前序遍历

他的访问顺序是:根节点→左子树→右子树

访问顺序为:A-B-C-D-E-F

//递归写法
    public static void preOrder(TreeNode tree) {
            if (tree == null)
                return;
            System.out.printf(tree.val + "");
            preOrder(tree.left);
            preOrder(tree.right);
        }
   //非递归写法
    public static void preOrder(TreeNode tree) {
           if (tree == null)
               return;
           Stack<TreeNode> q1 = new Stack<>();
           q1.push(tree);//压栈
           while (!q1.empty()) {
               TreeNode t1 = q1.pop();//出栈
               System.out.println(t1.val);
               if (t1.right != null) {
                    q1.push(t1.right);
                }
                if (t1.left != null) {
                    q1.push(t1.left);
                }
            }
        }

中序遍历

他的访问顺序是:左子树→根节点→右子树

所以下图中序遍历的结果是:C-B-D-A-E-F

访问顺序如下

//递归写法
   public static void inOrderTraversal(TreeNode node) {
           if (node == null)
               return;
           inOrderTraversal(node.left);
           System.out.println(node.val);
           inOrderTraversal(node.right);
       }
        //非递归的写法
        public static void inOrderTraversal(TreeNode tree) {
           Stack<TreeNode> stack = new Stack<>();
           while (tree != null || !stack.isEmpty()) {
               while (tree != null) {
                   stack.push(tree);
                   tree = tree.left;
               }
               if (!stack.isEmpty()) {
                   tree = stack.pop();
                    System.out.println(tree.val);
                    tree = tree.right;
                }
            }
      }

后序遍历

他的访问顺序是:左子树→右子树→根节点

所以上图前序遍历的结果是:C-D-B-F-E-A

//递归写法
   public static void postOrder(TreeNode tree) {
           if (tree == null)
                    return;
            postOrder(tree.left);
            postOrder(tree.right);
            System.out.println(tree.val);
        }
    //非递归的写法
        public static void postOrder(TreeNode tree) {
           if (tree == null)
               return;
         Stack<TreeNode> s1 = new Stack<>();
         Stack<TreeNode> s2 = new Stack<>();
         s1.push(tree);
         while (!s1.isEmpty()) {
             tree = s1.pop();
             s2.push(tree);
              if (tree.left != null) {
                  s1.push(tree.left);
              }
              if (tree.right != null) {
                  s1.push(tree.right);
              }
          }
          while (!s2.isEmpty()) {
              System.out.print(s2.pop().val + " ");
          }
      }
     //  或者
        public static void postOrder(TreeNode tree) {
           if (tree == null)
               return;
           Stack<TreeNode> stack = new Stack<>();
           stack.push(tree);
           TreeNode c;
           while (!stack.isEmpty()) {
               c = stack.peek();
               if (c.left != null && tree != c.left && tree != c.right) {
                    stack.push(c.left);
                } else if (c.right != null && tree != c.right) {
                    stack.push(c.right);
                } else {
                    System.out.print(stack.pop().val + " ");
                    tree = c;
                }
            }
        }

BFS广度优先遍历

他的访问顺序是:先访问上一层,在访问下一层,一层一层的往下访问

所以上图前序遍历的结果是:A→B→E→C→D→F

//  代码如下
        public static void levelOrder(TreeNode tree) {
          if (tree == null)
              return;
          LinkedList<TreeNode> list = new LinkedList<>();//链表,这里我们可以把它看做队列
          list.add(tree);//相当于把数据加入到队列尾部
          while (!list.isEmpty()) {
              TreeNode node = list.poll();//poll方法相当于移除队列头部的元素
              System.out.println(node.val);
              if (node.left != null)
                   list.add(node.left);
               if (node.right != null)
                   list.add(node.right);
           }
       }
   //     递归的写法
        public static void levelOrder(TreeNode tree) {
            int depth = depth(tree);
            for (int level = 0; level < depth; level++) {
                printLevel(tree, level);
            }
        }
        private static int depth(TreeNode tree) {
           if (tree == null)
                return 0;
            int leftDepth = depth(tree.left);
            int rightDepth = depth(tree.right);
            return Math.max(leftDepth, rightDepth) + 1;
        }
        private static void printLevel(TreeNode tree, int level) {
            if (tree == null)
                return;
            if (level == 0) {
                System.out.print(" " + tree.val);
            } else {
                printLevel(tree.left, level - 1);
                printLevel(tree.right, level - 1);
            }
        }
    //    如果想把遍历的结果存放到list中,我们还可以这样写
        public static List<List<Integer>> levelOrder(TreeNode tree) {
            if (tree == null)
                return null;
            List<List<Integer>> list = new ArrayList<>();
            bfs(tree, 0, list);
            return list;
        }
        private static void bfs(TreeNode tree, int level, List<List<Integer>> list) {
            if (tree == null)
                return;
            if (level >= list.size()) {
                List<Integer> subList = new ArrayList<>();
                subList.add(tree.val);
                list.add(subList);
            } else {
                list.get(level).add(tree.val);
            }
            bfs(tree.left, level + 1, list);
            bfs(tree.right, level + 1, list);
        }

DFS深度优先遍历

他的访问顺序是:先访根节点,然后左结点,一直往下,直到最左结点没有子节点的时候然后往上退一步到父节点,然后父节点的右子节点在重复上面步骤……

所以上图前序遍历的结果是:A→B→C→D→E→F

//    代码如下
      public static void treeDFS(TreeNode root) {
          Stack<TreeNode> stack = new Stack<>();
          stack.add(root);
          while (!stack.empty()) {
              TreeNode node = stack.pop();
              System.out.println(node.val);
              if (node.right != null) {
                  stack.push(node.right);
              }
               if (node.left != null) {
                   stack.push(node.left);
               }
           }
       }
       // 递归的写法
        public static void treeDFS(TreeNode root) {
            if (root == null)
                return;
            System.out.println(root.val);
            treeDFS(root.left);
            treeDFS(root.right);
        }


相关文章
|
14天前
|
存储 算法 Java
Java中,树与图的算法涉及二叉树的前序、中序、后序遍历以及DFS和BFS搜索。
【6月更文挑战第21天】Java中,树与图的算法涉及二叉树的前序、中序、后序遍历以及DFS和BFS搜索。二叉树遍历通过访问根、左、右子节点实现。DFS采用递归遍历图的节点,而BFS利用队列按层次访问。以下是简化的代码片段:[Java代码略]
19 4
|
10天前
|
存储 算法 Linux
【数据结构和算法】---二叉树(1)--树概念及结构
【数据结构和算法】---二叉树(1)--树概念及结构
12 0
|
15天前
|
存储 算法 程序员
数据结构与算法===递归
数据结构与算法===递归
|
14天前
|
算法 Java 机器人
Java数据结构与算法:AVL树
Java数据结构与算法:AVL树
|
9天前
|
机器学习/深度学习 数据采集 存储
算法金 | 决策树、随机森林、bagging、boosting、Adaboost、GBDT、XGBoost 算法大全
**摘要:** 这篇文章介绍了决策树作为一种机器学习算法,用于分类和回归问题,通过一系列特征测试将复杂决策过程简化。文章详细阐述了决策树的定义、构建方法、剪枝优化技术,以及优缺点。接着,文章讨论了集成学习,包括Bagging、Boosting和随机森林等方法,解释了它们的工作原理、优缺点以及如何通过结合多个模型提高性能和泛化能力。文中特别提到了随机森林和GBDT(XGBoost)作为集成方法的实例,强调了它们在处理复杂数据和防止过拟合方面的优势。最后,文章提供了选择集成学习算法的指南,考虑了数据特性、模型性能、计算资源和过拟合风险等因素。
12 0
算法金 | 决策树、随机森林、bagging、boosting、Adaboost、GBDT、XGBoost 算法大全
|
13天前
|
机器学习/深度学习 算法
梯度提升树GBDT系列算法
在Boosting集成算法当中,我们逐一建立多个弱评估器(基本是决策树),并且下一个弱评估器的建立方式依赖于上一个弱评估器的评估结果,最终综合多个弱评估器的结果进行输出。
|
15天前
|
Python
求解带有限重的三维装箱问题——启发式深度优先搜索算法
求解带有限重的三维装箱问题——启发式深度优先搜索算法
23 4
|
15天前
|
存储 算法 Python
python常用算法(5)——树,二叉树与AVL树(一)
python常用算法(5)——树,二叉树与AVL树
|
17天前
|
算法 数据可视化 Python
Python中的决策树算法探索
Python中的决策树算法探索
|
8天前
|
算法
技术好文共享:算法之树表的查找
技术好文共享:算法之树表的查找