【数据结构】二叉树的遍历

本文深入探讨了二叉树的基本概念,包括满二叉树和完全二叉树,并详细介绍了如何构建二叉树。接着,通过Java代码示例展示了前序、中序和后序遍历的方法,以及如何迭代实现。此外,还提供了计算二叉树高度和节点数的递归算法。这些内容对于理解和应用二叉树数据结构至关重要。
摘要由CSDN通过智能技术生成

二叉树是是一类非常重要的树形结构,在实际项目中,常用于决策分析、数据压缩、排序、查找、大规模数据索引等方面,最经典的哈夫曼算法也是基于这种数据结构。

本文主要讲解二叉树的构建、遍历、节点数以及高度的获取,且假设你已有树、链表的相关基础。

一、二叉树相关概念

1.1、二叉树

简单地理解,满足以下两个条件的树就是二叉树:

  1. 本身是有序树;
  2. 树中包含的各个节点的度不能超过 2,即只能是 0、1 或者 2;
1.2、满二叉树

如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树。

1.3、完全二叉树

如果二叉树中除去最后一层节点为满二叉树,且最后一层的结点依次从左到右分布,则此二叉树被称为完全二叉树.

二、二叉树的构建

构建二叉树,首先我们需要定义节点的数据类型、然后定义节点间的关系

2.1、构建二叉树节点数据结构

二叉树主要包括数据以及左右节点,这里以java代码举例,其中序列号index可根据实际需要移除该字段

public class TreeNode<T> {
    // 序列号
    private int index;
    // 数据
    private T data;
    // 左节点
    private TreeNode leftChild;
    // 右节点
    private TreeNode rightChild;

    public TreeNode(int index, T data) {
        this.index = index;
        this.data = data;
    }
}
2.2、构建二叉树

这里以 “ABCDE#F” 二叉树举例,其中#表示空节点

public class BinaryTree {
    // 根节点
    private TreeNode root = null;

    public BinaryTree() {
        root = new TreeNode(1, "A");
    }

    /**
     * 构建二叉树
     *         A
     *    B        C
     * D    E        F
     */
    public void createBinaryTree() {
        TreeNode nodeB = new TreeNode(2, "B");
        TreeNode nodeC = new TreeNode(3, "C");
        TreeNode nodeD = new TreeNode(4, "D");
        TreeNode nodeE = new TreeNode(5, "E");
        TreeNode nodeF = new TreeNode(6, "F");
        root.leftChild = nodeB;
        root.rightChild = nodeC;
        nodeB.leftChild = nodeD;
        nodeB.rightChild = nodeE;
        nodeC.rightChild = nodeF;
    }
}

三、二叉树的遍历

二叉树主要有三种遍历方法:前序遍历、中序遍历、后序遍历。另外层序遍历使用较少,且复杂度高。

3.1、前序遍历

定义:若二叉树为空,则空操作返回,否则先访问跟结点,然后前序遍历左子树,再前序遍历右子树。
前序遍历算法(DLR):中 -> 左 -> 右。

image-20220127202810611
/**
 * 前序遍历——迭代
 */
public void preOrder(TreeNode node){
    if(node == null){
        return;
    }else{
        System.out.println("preOrder data:"+node.getData());
        preOrder(node.leftChild);
        preOrder(node.rightChild);
    }
}

这里主要用到了递归的方式去遍历,下面提供可运行示例代码

public class BinaryTree {
    // 根节点
    private TreeNode root = null;

    public BinaryTree() {
        root = new TreeNode(1, "A");
    }

    /**
     * 构建二叉树
     *         A
     *    B        C
     * D    E        F
     */
    public void createBinaryTree() {
        TreeNode nodeB = new TreeNode(2, "B");
        TreeNode nodeC = new TreeNode(3, "C");
        TreeNode nodeD = new TreeNode(4, "D");
        TreeNode nodeE = new TreeNode(5, "E");
        TreeNode nodeF = new TreeNode(6, "F");
        root.leftChild = nodeB;
        root.rightChild = nodeC;
        nodeB.leftChild = nodeD;
        nodeB.rightChild = nodeE;
        nodeC.rightChild = nodeF;
    }

    /**
     * 前序遍历——迭代
     */
    public void preOrder(TreeNode node){
        if(node == null){
            return;
        }else{
            System.out.println("preOrder data:"+node.data);
            preOrder(node.leftChild);
            preOrder(node.rightChild);
        }
    }

    public class TreeNode<T> {
        // 序列号
        private int index;
        // 数据
        private T data;
        // 左节点
        private TreeNode leftChild;
        // 右节点
        private TreeNode rightChild;

        public TreeNode(int index, T data) {
            this.index = index;
            this.data = data;
        }
    }

    public static void main(String[] args) {
        BinaryTree binaryTree = new BinaryTree();
        binaryTree.createBinaryTree();
        binaryTree.preOrder(binaryTree.root);
    }
}

运行结果

image-20220127202810611
3.2、中序遍历

定义:若树为空,则空操作返回,否则从根结点开始(注意并不是先访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树
中序遍历算法(LDR):左 -> 中 -> 右。

image-20220127202810611
/**
 * 中序遍历——迭代
 */
public void midOrder(TreeNode node){
    if(node == null){
        return;
    }else{
        midOrder(node.leftChild);
        System.out.println("midOrder data:"+node.getData());
        midOrder(node.rightChild);
    }
}
3.3、后序遍历

定义:若树为空,则空操作返回,否则从左到右先叶子后结点的方式遍历访问左右子树,最后是访问根结点
后序遍历算法(LRD):左 -> 右 -> 中。

image-20220127202810611
/**
 * 后序遍历——迭代
 */
public void postOrder(TreeNode node){
    if(node == null){
        return;
    }else{
        postOrder(node.leftChild);
        postOrder(node.rightChild);
        System.out.println("postOrder data:"+node.getData());
    }
}
3.4、层序遍历

定义:若树为空,则空操作返回,否则从树的第一层,也就是根结点开始访问,从上而下逐层遍历,在同一层,按从左到右的顺序对结点逐个访问

image-20220127202810611

四、二叉树的高与节点数

4.1、二叉树的高

这里思路上同样需要应用递归,每递归一次层次+1,且将左右节点做大值作为该层的高。

/**
 * 求二叉树的高度
 */
public int getHeight(){
    return getHeight(root);
}

private int getHeight(TreeNode node) {
    if(node == null){
        return 0;
    }else{
        int i = getHeight(node.leftChild);
        int j = getHeight(node.rightChild);
        return (i<j)?j+1:i+1;
    }
}
4.2、二叉树的节点数

这里思路上同样需要应用递归,将左右节点数相加起来作为该层的总节点数。

/**
 * 获取二叉树的结点数
 */
public int getSize(){
    return getSize(root);
}


private int getSize(TreeNode node) {
    if(node == null){
        return 0;
    }else{
        return 1+getSize(node.leftChild)+getSize(node.rightChild);
    }
}

五、demo实例

import java.util.Stack;

public class BinaryTree {
    private TreeNode  root = null;

    public BinaryTree(){
        root = new TreeNode(1, "A");
    }

    /**
     * 构建二叉树
     *         A
     *     B       C
     * D      E        F
     */
    public void createBinaryTree(){
        TreeNode nodeB = new TreeNode(2, "B");
        TreeNode nodeC = new TreeNode(3, "C");
        TreeNode nodeD = new TreeNode(4, "D");
        TreeNode nodeE = new TreeNode(5, "E");
        TreeNode nodeF = new TreeNode(6, "F");
        root.leftChild = nodeB;
        root.rightChild = nodeC;
        nodeB.leftChild = nodeD;
        nodeB.rightChild = nodeE;
        nodeC.rightChild = nodeF;
    }

    /**
     * 求二叉树的高度
     * @author Administrator
     *
     */
    public int getHeight(){
        return getHeight(root);
    }

    private int getHeight(TreeNode node) {
        if(node == null){
            return 0;
        }else{
            int i = getHeight(node.leftChild);
            int j = getHeight(node.rightChild);
            return (i<j)?j+1:i+1;
        }
    }

    /**
     * 获取二叉树的结点数
     * @author Administrator
     *
     */
    public int getSize(){
        return getSize(root);
    }


    private int getSize(TreeNode node) {
        if(node == null){
            return 0;
        }else{
            return 1+getSize(node.leftChild)+getSize(node.rightChild);
        }
    }

    /**
     * 前序遍历——迭代
     * @author Administrator
     *
     */
    public void preOrder(TreeNode node){
        if(node == null){
            return;
        }else{
            System.out.println("preOrder data:"+node.getData());
            preOrder(node.leftChild);
            preOrder(node.rightChild);
        }
    }

    /**
     * 前序遍历——非迭代
     */

    public void nonRecOrder(TreeNode node){
        if(node == null){
            return;
        }
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(node);
        while(!stack.isEmpty()){
            //出栈和进栈
            TreeNode n = stack.pop();//弹出根结点
            //压入子结点
            System.out.println("nonRecOrder data"+n.getData());
            if(n.rightChild!=null){
                stack.push(n.rightChild);

            }
            if(n.leftChild!=null){
                stack.push(n.leftChild);
            }
        }
    }
    /**
     * 中序遍历——迭代
     * @author Administrator
     *
     */
    public void midOrder(TreeNode node){
        if(node == null){
            return;
        }else{
            midOrder(node.leftChild);
            System.out.println("midOrder data:"+node.getData());
            midOrder(node.rightChild);
        }
    }

    /**
     * 后序遍历——迭代
     * @author Administrator
     *
     */
    public void postOrder(TreeNode node){
        if(node == null){
            return;
        }else{
            postOrder(node.leftChild);
            postOrder(node.rightChild);
            System.out.println("postOrder data:"+node.getData());
        }
    }
    public class TreeNode<T>{
        private int index;
        private T data;
        private TreeNode leftChild;
        private TreeNode rightChild;


        public int getIndex() {
            return index;
        }


        public void setIndex(int index) {
            this.index = index;
        }


        public T getData() {
            return data;
        }


        public void setData(T data) {
            this.data = data;
        }


        public TreeNode(int index,T data){
            this.index = index;
            this.data = data;
            this.leftChild = null;
            this.rightChild = null;
        }
    }


    public static void main(String[] args){
        BinaryTree binaryTree = new BinaryTree();
        binaryTree.createBinaryTree();
        int height = binaryTree.getHeight();
        System.out.println("treeHeihgt:"+height);
        int size = binaryTree.getSize();
        System.out.println("treeSize:"+size);
//		binaryTree.preOrder(binaryTree.root);
//		binaryTree.midOrder(binaryTree.root);
//		binaryTree.postOrder(binaryTree.root);
        binaryTree.nonRecOrder(binaryTree.root);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流星雨在线

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值