数据结构与算法分析----二叉树+前序+中序+后序遍历

二叉树概述

知道单链表吧,单链表每个节点只能由一个后继节点。一个链表,假设他每个节点都可以有不多于两个的后继节点,那么他就可以被称为二叉树,此时,这个二叉树中的节点被称为结点,二叉树的后继结点又被称为子结点,且有着左右之分,一个结点的左边的子结点为左子结点,右边的为右子结点。
如:
在这里插入图片描述源自百度百科
这里的每个字母都代表着一个结点
二叉树不一定要由链表实现,他是一种数据结构,是一种结构,只要有着这种结构的都可以称为二叉树
百度百科:
二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树,且有左右之分。
相关术语:
①结点:包含一个数据元素及若干指向子树分支的信息。
②结点的度:一个结点拥有子树的数目称为结点的度。
③叶子结点:也称为终端结点,没有子树的结点或者度为零的结点。
④分支结点:也称为非终端结点,度不为零的结点称为非终端结点。
⑤树的度:树中所有结点的度的最大值。
⑥结点的层次:从根结点开始,假设根结点为第1层,根结点的子节点为第2层,依此类推,如果某一个结点位于第L层,则其子节点位于第L+1层。
⑦树的深度:也称为树的高度,树中所有结点的层次最大值称为树的深度。
⑧有序树:如果树中各棵子树的次序是有先后次序,则称该树为有序树。
⑨无序树:如果树中各棵子树的次序没有先后次序,则称该树为无序树。
⑩森林:由m(m≥0)棵互不相交的树构成一片森林。如果把一棵非空的树的根结点删除,则该树就变成了一片森林,森林中的树由原来根结点的各棵子树构成。

两种特殊的二叉树:
1、满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
2、完全二叉树:深度为k,有n个结点的二叉树当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应时,称为完全二叉树。
完全二叉树的特点是叶子结点只可能出现在层序最大的两层上,并且某个结点的左分支下子孙的最大层序与右分支下子孙的最大层序相等或大1。

简单来说,完全二叉树:结点倒数第二层为满,倒数第一层最左边必定有一个结点,且从左边到右边连续,所谓的连续就是两个叶子结点之间不能有空位
满二叉树是完全二叉树,完全二叉树不一定是满二叉树
在这里插入图片描述源自百度百科
国内的满二叉树的定义和国外的满二叉树的定义有一点不同,不用在意

遍历

遍历是对树的一种最基本的运算,所谓遍历二叉树,就是按一定的规则和顺序走遍二叉树的所有结点,使每一个结点都被访问一次,而且只被访问一次。由于二叉树是非线性结构,因此,树的遍历实质上是将二叉树的各个结点转换成为一个线性序列来表示。
遍历有三种方式,前序,中序,后续:
三种遍历方式的区别在于父结点什么时候打印,
若先输出父结点,则是前序。
若输入顺序是:子结点 父结点 子结点 则中序
若输入顺序是:子结点 子结点 父结点 则后序
这里我们用递归来实现对二叉树的遍历
这些遍历的递归确实不太好理解为啥就能遍历完一整棵树,可以结合deBug走一遍理解理解

先创建一个二叉树

我们需要创建一个结点类:
在这里插入图片描述
我们创建一个稍微复杂一点的树,这样遍历起来更可观
创建一个这样结构的树:
在这里插入图片描述
这样创建:
在这里插入图片描述

前序遍历

何为前序遍历?在递归的过程中,先打印当前结点,然后向左子结点递归,左边递归完成,再向右子结点递归
如图:在这里插入图片描述
每次递归先打印出当前结点,首先传入根结点,打印当前结点,然后向左子结点递归,一直向左直到左子结点到尽头,即node==null,然后开始回溯,则退出这次递归,然后就是向右的递归,也直到右子结点到尽头,然后在回溯,回溯到这些结点的父节点,再在父结点的根基下向左和向右递归,直到最后退出整个递归体,即遍历完成
打印结果:
在这里插入图片描述在这里插入图片描述
顺序是:0,1,3,4,7,9,10,11,12,13,2,5,6,8
确实正确

中序遍历

何为中序遍历?在递归的过程中,先向左递归,左边递归完成,然后打印当前节点,再向右子结点递归
在这里插入图片描述
先向左递归,直到到左边结点到尽头,然后打印当前结点,然后在当前结点的基础上向右递归,再到尽头,则回溯,跟上面的前序遍历一个道理,都是递归回溯
在这里插入图片描述在这里插入图片描述
打印顺序:3,1,9,7,11,10,13,12,4,0,5,2,6,8,没问题

后续遍历

何为后序遍历?在递归的过程中,先向左递归,左边递归完成,向右递归,右边递归完成打印当前节点
在这里插入图片描述
靠的就是在回溯的过程中进行打印
先向左递归,到尽头,再在当前结点的基础上向右递归,到尽头则打印当前结点,然后回溯
在这里插入图片描述在这里插入图片描述
顺序:3,9,11,13,12,10,7,4,1,5,8,6,2,0

代码

package com.LYH.structure.Nonlinearity.Tree;

public class BinaryTreeTraversal {
    
    
    public static void main(String[] args) {
    
    
        BinaryTree tree=new BinaryTree();

//        创建14个结点
        Node[] Nodes=new Node[14];
        for (int i = 0; i < 14; i++) {
    
    
            Nodes[i]=new Node(i,"牛蛙"+i+"号");
        }
//        构建结构
        Nodes[0].setLeft(Nodes[1]);
        Nodes[0].setRight(Nodes[2]);
        Nodes[1].setLeft(Nodes[3]);
        Nodes[1].setRight(Nodes[4]);
        Nodes[2].setLeft(Nodes[5]);
        Nodes[2].setRight(Nodes[6]);
        Nodes[4].setLeft(Nodes[7]);
        Nodes[6].setRight(Nodes[8]);
        Nodes[7].setLeft(Nodes[9]);
        Nodes[7].setRight(Nodes[10]);
        Nodes[10].setLeft(Nodes[11]);
        Nodes[10].setRight(Nodes[12]);
        Nodes[12].setLeft(Nodes[13]);
        tree.setRoot(Nodes[0]);
        tree.Traversal();
}
class BinaryTree{
    
    
    private Node root;

    public Node getRoot() {
    
    
        return root;
    }

    public void setRoot(Node root) {
    
    
        this.root = root;
    }
//    三种遍历方式的区别在于父节点什么时候打印,
//    若先输出父节点,则是前序。
//    若输入顺序是:子节点 父节点 子节点   则中序
//    若输入顺序是:子节点 子节点 父节点   则后序

//    遍历
    public void Traversal(){
    
    
        if (root==null){
    
    
            System.out.println("树为空");
        }else {
    
    
//            PreorderTraversal(root); //前序
//            PostorderTraversal(root);//后序
            InfixTraversal(root); //中序
        }
    }
//    前序
    private void PreorderTraversal(Node node){
    
    
        if (node!=null){
    
    
            System.out.println(node);
            PreorderTraversal(node.getLeft());
            PreorderTraversal(node.getRight());
        }
    }

//    中序
    private void InfixTraversal(Node node){
    
    
        if (node!=null){
    
    
            InfixTraversal(node.getLeft());
            System.out.println(node);
            InfixTraversal(node.getRight());
        }
    }

//    后序
    private void PostorderTraversal(Node node){
    
    
        if (node!=null){
    
    
            PostorderTraversal(node.getLeft());
            PostorderTraversal(node.getRight());
            System.out.println(node);
        }
    }
}
class Node{
    
      //假设我们这个结点类存储用户的id和姓名(name)
    private int id;
    private String name;
    private Node left;  //左子结点
    private Node right;  //右子结点

    public Node(int id, String name) {
    
    
        this.id = id;
        this.name = name;
    }

    public Node() {
    
    
    }
    public void setId(int id) {
    
    
        this.id = id;
    }
    public void setName(String name) {
    
    
        this.name = name;
    }
    public void setLeft(Node left) {
    
    
        this.left = left;
    }
    public void setRight(Node right) {
    
    
        this.right = right;
    }
    public int getId() {
    
    
        return id;
    }
    public String getName() {
    
    
        return name;
    }
    public Node getLeft() {
    
    
        return left;
    }
    public Node getRight() {
    
    
        return right;
    }
    @Override
    public String toString() {
    
    
        return "Node{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}

猜你喜欢

转载自blog.csdn.net/qq_45821251/article/details/121453954