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

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

基本概念

树是一个有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);
        }


相关文章
|
1月前
|
算法 测试技术 定位技术
数据结构与算法——DFS(深度优先搜索)
数据结构与算法——DFS(深度优先搜索)
|
3月前
|
存储 算法 C语言
"揭秘C语言中的王者之树——红黑树:一场数据结构与算法的华丽舞蹈,让你的程序效率飙升,直击性能巅峰!"
【8月更文挑战第20天】红黑树是自平衡二叉查找树,通过旋转和重着色保持平衡,确保高效执行插入、删除和查找操作,时间复杂度为O(log n)。本文介绍红黑树的基本属性、存储结构及其C语言实现。红黑树遵循五项基本规则以保持平衡状态。在C语言中,节点包含数据、颜色、父节点和子节点指针。文章提供了一个示例代码框架,用于创建节点、插入节点并执行必要的修复操作以维护红黑树的特性。
101 1
|
8天前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
25 2
|
9天前
|
算法
树的遍历算法有哪些?
不同的遍历算法适用于不同的应用场景。深度优先搜索常用于搜索、路径查找等问题;广度优先搜索则在图的最短路径、层次相关的问题中较为常用;而二叉搜索树的遍历在数据排序、查找等方面有重要应用。
18 2
|
1月前
|
算法 搜索推荐 Shell
数据结构与算法学习十二:希尔排序、快速排序(递归、好理解)、归并排序(递归、难理解)
这篇文章介绍了希尔排序、快速排序和归并排序三种排序算法的基本概念、实现思路、代码实现及其测试结果。
20 1
|
1月前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
18 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
2月前
|
大数据 UED 开发者
实战演练:利用Python的Trie树优化搜索算法,性能飙升不是梦!
在数据密集型应用中,高效搜索算法至关重要。Trie树(前缀树/字典树)通过优化字符串处理和搜索效率成为理想选择。本文通过Python实战演示Trie树构建与应用,显著提升搜索性能。Trie树利用公共前缀减少查询时间,支持快速插入、删除和搜索。以下为简单示例代码,展示如何构建及使用Trie树进行搜索与前缀匹配,适用于自动补全、拼写检查等场景,助力提升应用性能与用户体验。
54 2
|
1月前
|
存储 算法
数据结构与算法学习十六:树的知识、二叉树、二叉树的遍历(前序、中序、后序、层次)、二叉树的查找(前序、中序、后序、层次)、二叉树的删除
这篇文章主要介绍了树和二叉树的基础知识,包括树的存储方式、二叉树的定义、遍历方法(前序、中序、后序、层次遍历),以及二叉树的查找和删除操作。
24 0
|
1月前
|
算法 定位技术
数据结构与算法学习九:学习递归。递归的经典实例:打印问题、阶乘问题、递归-迷宫问题、八皇后问题
本文详细介绍了递归的概念、重要规则、形式,并展示了递归在解决打印问题、阶乘问题、迷宫问题和八皇后问题等经典实例中的应用。
38 0