二叉树的遍历算法

简介: 二叉树的遍历算法

公众号merlinsea


  • 树的介绍
  • 树是一种非线性的数据结构,即树从一个节点出发可能有多个后继节点。
  • 树的基本术语
  • 节点: A、B、C等元素都是节点,节点不仅包含了数据元素,还包含了指向子树的分支。
  • 节点的度:节点拥有的子树的个数或者分支的个数,比如节点A有三个子树,因此节点A的度为3,节点B有两个子树,因此节点B的度是2
  • 树的度:树中各个节点中度的最大值定义为整颗树的度。比如下面这棵树的度是3
  • 叶子节点:指的是没有子树的节点叫做树的叶子节点,比如下图中的K、L、F、G、M、I、J
  • 内部节点: 指的是除叶子节点意外的其他节点叫内部节点,比如下图中的A、B、C、D、E、H
  • 孩子节点:某一节点的子树称之为改节点的孩子节点,比如A节点的孩子节点是B、C、D
  • 双亲节点:与孩子节点向电影院的节点是双亲节点,比如B节点的双亲是A
  • 兄弟节点:统一节点的孩子节点之间称之为兄弟节点,比如B节点的兄弟节点是C和D
  • 树的高度:从根节点开始所能到达叶子节点中距离最长路径长度称之为树的高度,比如下图的树高是4


640.png


  • 二叉树的定义
  • 每个节点最多只能有两个孩子节点,即二叉树中节点的度只可以为0,1,2
  • 子树有左右之分,不能颠倒,分别称之为左孩子和右孩子。
  • 特殊的二叉树
  • 满二叉树:如果二叉树所有的内部节点都有左右孩子节点,并且所有的孩子节点都集中在同一层中,这样的二叉树称之为满二叉树。
  • 完全二叉树:从上到下,从左到右紧密的排布,不跳跃任何一个位置的二叉树就是完全二叉,比如下图中去掉G节点的右边的树就是一颗完全二叉树,满二叉树是一种特殊的完全二叉树。

640.png


  • 树的顺序存储结构
  • 特点:要求是一颗完全二叉树或者把一颗普通的二叉树补齐虚拟节点保证补齐以后是一颗完全二叉树,然后采用数组的方式进行存储。


640.png


  • 二叉树的链式存储

640.png


public class BTNode {
    public int val;
    public String info;
    public BTNode left;
    public BTNode right;
    public BTNode(){
        val = 0;
        info = "";
        left = right = null;
    }
    public BTNode(int val,String info){
        this.val = val;
        this.info = info;
    }
    @Override
    public String toString() {
        return "BTNode{" +
                "val=" + val +
                ", info='" + info + '\'' +
                '}';
    }
}


  • 二叉树的先序遍历算法(链式存储)
  • 先序遍历的遍历顺序是先访问根节点,然后访问左子树,最后访问右子树的过程。
  • 遍历结果: A,B,D,C,E,F

640.png


  • 先序遍历递归版本代码实现


public class Main {
    public static void main(String[] args) {
        BTNode root = create();
        preOrder(root);
    }
    public static void preOrder(BTNode root){
        if(root == null){
            return;
        }
        System.out.println(root);
        //递归调用左边
        preOrder(root.left);
        //递归调用右边
        preOrder(root.right);
    }
    public static BTNode create(){
        BTNode a = new BTNode(0,"A");
        BTNode b = new BTNode(1,"B");
        BTNode c = new BTNode(2,"C");
        BTNode d = new BTNode(3,"D");
        BTNode e = new BTNode(4,"E");
        BTNode f = new BTNode(5,"F");
        a.left = b;
        a.right = c;
        b.left = d;
        c.left = e;
        c.right = f;
        return a;
    }
}
  • 先序遍历非递归版本代码实现
  • 当我们访问到父节点的时候,其实我们在这个时候同时遇见了父节点的左孩子和右孩子,但先序遍历要求先处理了左孩子,再处理右孩子,因此此时我们应该先将右孩子入栈,等访问玩左孩子以后,通过出栈操作可以访问右孩子。


public class Main2 {
    public static void main(String[] args) {
        BTNode root = create();
        preOrderNoCur(root);
    }
    public static void preOrderNoCur(BTNode root){
        if(root == null){
            return;
        }
        Stack<BTNode> stack = new Stack<>();
        //初始化
        stack.push(root);
        //遍历
        while(!stack.empty()){
            BTNode p = stack.pop();
            System.out.println(p);
            if(p.right!=null){
                stack.push(p.right);
            }
            if(p.left!=null){
                stack.push(p.left);
            }
        }
    }
    public static BTNode create(){
        BTNode a = new BTNode(0,"A");
        BTNode b = new BTNode(1,"B");
        BTNode c = new BTNode(2,"C");
        BTNode d = new BTNode(3,"D");
        BTNode e = new BTNode(4,"E");
        BTNode f = new BTNode(5,"F");
        a.left = b;
        a.right = c;
        b.left = d;
        c.left = e;
        c.right = f;
        return a;
    }
}


  • 二叉树的中序遍历算法(链式存储)
  • 中序遍历的遍历顺序是先访问左子树,然后访问根,最后访问右子树的过程。
  • 遍历结果:D、B、A、E、C、F

640.png

  • 中序遍历递归版本代码实现


public class Main {
    public static void main(String[] args) {
        BTNode root = create();
        inOrder(root);
    }
    public static void inOrder(BTNode root){
        if(root == null){
            return;
        }
        inOrder(root.left);
        System.out.println(root);
        inOrder(root.right);
    }
    public static BTNode create(){
        BTNode a = new BTNode(0,"A");
        BTNode b = new BTNode(1,"B");
        BTNode c = new BTNode(2,"C");
        BTNode d = new BTNode(3,"D");
        BTNode e = new BTNode(4,"E");
        BTNode f = new BTNode(5,"F");
        a.left = b;
        a.right = c;
        b.left = d;
        c.left = e;
        c.right = f;
        return a;
    }
}


  • 中序遍历非递归版本代码实现
  • 当我们遇见A节点的时候,我们需要先处理A.left,处理完以后再处理A,因此A需要夏安入栈
  • 递归->非递归 : 核心点是当前我们遇见了A,但不能立即处理A,需要先处理A.left再处理A,因此栈具有记忆性特征。

640.png

public class Main2 {
    public static void main(String[] args) {
        BTNode root = create();
        inOrderNoCur(root);
    }
    public static void inOrderNoCur(BTNode root){
        if(root == null){
            return;
        }
        Stack<BTNode> stack = new Stack<>();
        BTNode p = root;
        while(p!=null || !stack.empty()){
            if(p!=null){
                stack.push(p);
                p = p.left;
            }else{
                p = stack.pop();
                System.out.println(p);
                p = p.right;
            }
        }
    }
    public static BTNode create(){
        BTNode a = new BTNode(0,"A");
        BTNode b = new BTNode(1,"B");
        BTNode c = new BTNode(2,"C");
        BTNode d = new BTNode(3,"D");
        BTNode e = new BTNode(4,"E");
        BTNode f = new BTNode(5,"F");
        a.left = b;
        a.right = c;
        b.left = d;
        c.left = e;
        c.right = f;
        return a;
    }
}


  • 二叉树的后序遍历算法(链式存储)
  • 后序遍历的遍历顺序是先访问左子树,然后访问右子树,最后访问根的过程。
  • 遍历结果:D、B、E、F、C、A

640.png


  • 后序遍历递归版本代码实现


public class Main {
    public static void main(String[] args) {
        BTNode root = create();
        postOrder(root);
    }
    public static void postOrder(BTNode root){
        if(root == null){
            return;
        }
        postOrder(root.left);
        postOrder(root.right);
        System.out.println(root);
    }
    public static BTNode create(){
        BTNode a = new BTNode(0,"A");
        BTNode b = new BTNode(1,"B");
        BTNode c = new BTNode(2,"C");
        BTNode d = new BTNode(3,"D");
        BTNode e = new BTNode(4,"E");
        BTNode f = new BTNode(5,"F");
        a.left = b;
        a.right = c;
        b.left = d;
        c.left = e;
        c.right = f;
        return a;
    }
}


  • 后序遍历非递归版本代码实现


public class Main2 {
    public static void main(String[] args) {
        BTNode root = create();
        postOrderNoCur(root);
    }
    public static void postOrderNoCur(BTNode root){
        if(root == null){
            return;
        }
        Stack<BTNode> stack = new Stack<>();
        BTNode p = root;
        //最近一次访问的节点
        BTNode lastVisitedNode = null;
        while(p!=null || !stack.empty()){
            if(p!=null){
                stack.push(p);
                p = p.left;
            }else{
               p = stack.peek();
               if(p.right==null || lastVisitedNode == p.right){
                   stack.pop();
                   //说明是从右子树往回走
                   System.out.println(p);
                   //标记最近访问的节点
                   lastVisitedNode = p;
                   // p=null是 为了继续往回走
                   p = null;
               }else{
                   //说明是从左子树往回走
                   p = p.right;
               }
            }
        }
    }
    public static BTNode create(){
        BTNode a = new BTNode(0,"A");
        BTNode b = new BTNode(1,"B");
        BTNode c = new BTNode(2,"C");
        BTNode d = new BTNode(3,"D");
        BTNode e = new BTNode(4,"E");
        BTNode f = new BTNode(5,"F");
        a.left = b;
        a.right = c;
        b.left = d;
        c.left = e;
        c.right = f;
        return a;
    }
}  


  • 总结以上三种遍历算法的路程流转图
  • 在二叉树遍历的过程中,不论是先序遍历,中序遍历还是后序遍历,均按照这个流程来进行。
  • 第1次遇见就输出,则是先序遍历;
  • 第2次遇见就输出,则是中序遍历;
  • 第3次遇见就输出,则是后序遍历;

640.png


  • 二叉树的层序遍历(链式存储)
  • 层序遍历,顾名思义就是按照二叉树的层次结构一层一层的访问。
  • 下面这个二叉树的层序遍历访问结果是:A、B、C、D、E、F


640.png


  • 层序遍历代码实现


public class Main {
    public static void main(String[] args) {
        BTNode root = create();
        layerOrder(root);
    }
    public static void layerOrder(BTNode root){
        if(root == null){
            return;
        }
        Queue<BTNode> queue = new LinkedList<>();
        //队列初始化
        queue.offer(root);
        //层序遍历
        while (!queue.isEmpty()){
            BTNode cur = queue.poll();
            System.out.println(cur);
            if(cur.left!=null){
                queue.offer(cur.left);
            }
            if(cur.right!=null){
                queue.offer(cur.right);
            }
        }
    }
    public static BTNode create(){
        BTNode a = new BTNode(0,"A");
        BTNode b = new BTNode(1,"B");
        BTNode c = new BTNode(2,"C");
        BTNode d = new BTNode(3,"D");
        BTNode e = new BTNode(4,"E");
        BTNode f = new BTNode(5,"F");
        a.left = b;
        a.right = c;
        b.left = d;
        c.left = e;
        c.right = f;
        return a;
    }
}


相关文章
|
8天前
|
算法
分享一些提高二叉树遍历算法效率的代码示例
这只是简单的示例代码,实际应用中可能还需要根据具体需求进行更多的优化和处理。你可以根据自己的需求对代码进行修改和扩展。
|
11天前
|
存储 缓存 算法
如何提高二叉树遍历算法的效率?
选择合适的遍历算法,如按层次遍历树时使用广度优先搜索(BFS),中序遍历二叉搜索树以获得有序序列。优化数据结构,如使用线索二叉树减少空指针判断,自定义节点类增加辅助信息。利用递归与非递归的特点,避免栈溢出问题。多线程并行遍历提高速度,注意线程安全。缓存中间结果,避免重复计算。预先计算并存储信息,提高遍历效率。综合运用这些方法,提高二叉树遍历算法的效率。
32 5
|
11天前
|
算法
树的遍历算法有哪些?
不同的遍历算法适用于不同的应用场景。深度优先搜索常用于搜索、路径查找等问题;广度优先搜索则在图的最短路径、层次相关的问题中较为常用;而二叉搜索树的遍历在数据排序、查找等方面有重要应用。
20 2
|
14天前
|
机器学习/深度学习 JSON 算法
二叉树遍历算法的应用场景有哪些?
【10月更文挑战第29天】二叉树遍历算法作为一种基础而重要的算法,在许多领域都有着不可或缺的应用,它为解决各种复杂的问题提供了有效的手段和思路。随着计算机科学的不断发展,二叉树遍历算法也在不断地被优化和扩展,以适应新的应用场景和需求。
24 0
|
1月前
|
存储 算法 关系型数据库
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
这篇文章主要介绍了多路查找树的基本概念,包括二叉树的局限性、多叉树的优化、B树及其变体(如2-3树、B+树、B*树)的特点和应用,旨在帮助读者理解这些数据结构在文件系统和数据库系统中的重要性和效率。
20 0
数据结构与算法学习二一:多路查找树、二叉树与B树、2-3树、B+树、B*树。(本章为了解基本知识即可,不做代码学习)
|
1月前
|
存储 算法 搜索推荐
数据结构与算法学习十七:顺序储存二叉树、线索化二叉树
这篇文章主要介绍了顺序存储二叉树和线索化二叉树的概念、特点、实现方式以及应用场景。
21 0
数据结构与算法学习十七:顺序储存二叉树、线索化二叉树
|
1月前
|
存储 算法
【二叉树】—— 算法题
【二叉树】—— 算法题
【二叉树】—— 算法题
|
1月前
|
存储 算法
数据结构与算法学习十六:树的知识、二叉树、二叉树的遍历(前序、中序、后序、层次)、二叉树的查找(前序、中序、后序、层次)、二叉树的删除
这篇文章主要介绍了树和二叉树的基础知识,包括树的存储方式、二叉树的定义、遍历方法(前序、中序、后序、层次遍历),以及二叉树的查找和删除操作。
24 0
|
3月前
|
算法
【初阶数据结构篇】二叉树算法题
二叉树是否对称,即左右子树是否对称.
27 0
|
26天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。