数据结构学习笔记(三)之 二叉树的遍历

欢迎移步博主小站:白亮吖雅黑丫の小站

数据结构之树与二叉树的学习(一)

简介

本文主要对数据结构中的树与二叉树进行学习,之前我们学习了数据的线性结构(线性表),但数据之间不只有这种简单的一对一关系,更多时候是一对多,甚至多对多的结构,而树结构作为一种比线性结构更复杂的数据结构,比较适合于描述具有层次关系的数据,即数据间的一对多关系。


定义

树中常常将数据元素称之为结点,树是n个结点的集合。当n=0时,称为空树;任意一颗非空树都满足一下几个条件:

  • 有且仅有一个特定的称为根的结点
  • 当n>1时,除根结点之外的其余结点被分为m个互不相交的有限集合,其中每一个集合又是一棵树

基本术语

  • 结点的度与树的度
  • 叶子结点与分支结点
  • 孩子结点、双亲结点、兄弟结点
  • 路径、路径长度
  • 祖先、子孙
  • 结点的层数、树的深度(高度)
  • 层序编号
  • 有序树、无序树
  • 森林

二叉树

定义

二叉树是n个结点的有限集合,该集合或者为空集,或者由一个根结点和2棵互不相交的、分别称为根节点的左子树和柚子乎上的二叉树构成。

二叉树的特点

  • 每个结点最多有2棵子树
  • 二叉树是有序的,次序不能颠倒

基本术语

  • 斜树
  • 满二叉树
  • 完全二叉树

二叉树的遍历

简介

二叉树的存储可以采用顺序存储和连接存储两种方式,相应的代码实现也有些许区别,不过其思想都是一致的,下面我们针对链接存储结构来实现二叉树的几种遍历方式。

二叉树的构造及其基本操作:

package com.dataStructure;

/**
 * author zbl
 *
 * datetime 2019.11.266666
 *
 */
//结点类
public class TreeNode<T> {
    //指向下一个结点
    public TreeNode leftChild;
    public TreeNode rightChild;
    public T data;

    TreeNode(T data){
        this.data = data;
    }


}

构架二叉树函数代码实现:

  • 此处采用迭代左子树实现,创建的是一棵左斜树
//创建二叉树
    private TreeNode creatBiTree(LinkedList<T> inputList){
        TreeNode<T> tmp = null;
        //判空
        if(inputList == null || inputList.isEmpty()){
            return null;
        }
        //存数
        T data = inputList.removeFirst();
        if(data != null){
            tmp = new TreeNode(data);
            tmp.leftChild = this.creatBiTree(inputList);
            tmp.rightChild = this.creatBiTree(inputList);
        }
        //返回根结点
        return tmp;
    }

前序遍历

输出顺序:根节点、左子树、右子树

递归代码实现:

//前序遍历  递归实现
    private void preOrder(TreeNode<T> node){
        if (node != null){
            System.out.println(node.data);
            preOrder(node.leftChild);
            preOrder(node.rightChild);
        }
    }

非递归代码实现:

//前序遍历 非递归
    private void preOrder(TreeNode<T> node){
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode<T> tmp = this.node;
        while(tmp != null || !stack.isEmpty()){
            //迭代访问节点的左孩子,并入栈
            while(tmp != null){
                System.out.println(tmp.data);
                stack.push(tmp);
                tmp = tmp.leftChild;
            }
            //如果节点没有左孩子,则弹出栈顶,访问节点右孩子
            if(!stack.isEmpty()){
                tmp = stack.pop();
                tmp = tmp.rightChild;
            }
        }
    }

中序遍历

输出顺序:左子树、根节点、右子树

递归代码实现:

//中序遍历 递归实现
    private void inOrder(TreeNode<T> node){
        if (node != null){
            inOrder(node.leftChild);
            System.out.println(node.data);
            inOrder(node.rightChild);
        }
    }

非递归代码实现:

//中序遍历 非递归
    private void inOrder(TreeNode<T> node){
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode<T> tmp = this.node;
        //当节点不为空,且栈不为空
        while(tmp != null || !stack.isEmpty()){
            //迭代访问节点的左孩子,并入栈
            while(tmp != null){
                stack.push(tmp);
                tmp = tmp.leftChild;
            }
            //访问叶子节点
            System.out.println(tmp.data);
            //栈非空,说明还未遍历完
            if(!stack.isEmpty()){
                //父节点出栈
                tmp = stack.pop();
                //访问父节点
                System.out.println(tmp.data);
                //访问右子树
                tmp = tmp.rightChild;
            }
        }
    }
后序遍历

输出顺序:左子树、右子树、根节点

递归代码实现:

//后序遍历  递归实现
    private void postOrder(TreeNode<T> node){
        if (node != null){
            postOrder(node.leftChild);
            postOrder(node.rightChild);
            System.out.println(node.data);
        }
    }

非递归代码实现:

//后序遍历 非递归
    private void postOrder(TreeNode<T> node){
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode<T> tmp = this.node;
        while(tmp != null || !stack.isEmpty()){
            while(tmp != null){
                stack.push(tmp);
                tmp = tmp.leftChild;
            }
            if(!stack.isEmpty()){
                tmp = stack.pop();
                //若为叶子节点,访问
                if(tmp.rightChild == null)
                    System.out.println(tmp.data);
                tmp = tmp.rightChild;
            }
        }
    }
层序遍历

按照从根节点到叶子节点的层次关系进行遍历,属于广度优先遍历。
非递归代码实现:

//层序遍历 非递归实现
    public void LerverOrder(){
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        //根节点入队
        queue.offer(node);
        System.out.println("层序遍历开始");
        while(!queue.isEmpty()){
            TreeNode<T> tmp = queue.poll();
            System.out.println(tmp.data);
            if(tmp.leftChild != null)
                queue.offer(tmp.leftChild);
            if(tmp.rightChild != null)
                queue.offer(tmp.rightChild);
        }
        System.out.println("层序遍历结束");
    }

完整Java代码

BiTreeOrder遍历接口:

package com.dataStructure;

public interface BiTreeOrder {
    //前序遍历
    public void PreOrder();
    //中序遍历
    public void InOrder();
    //后序遍历
    public void PostOrder();
    //层序遍历
    public void LerverOrder();

}

ReBiTree递归实现类:

package com.dataStructure;

import sun.reflect.generics.tree.Tree;

import java.util.LinkedList;
import java.util.Queue;

/**
 * author zbl
 *
 * datetime 2019.11.266666
 *
 */
public class ReBiTree<T> implements BiTreeOrder{

    //存根结点
    protected TreeNode<T> node = null;

    //构造函数
    public ReBiTree(LinkedList<T> inputList){
        this.node = this.creatBiTree(inputList);
    }

    //空构造函数
    public ReBiTree() {

    }

//    public void addBiTree()
    //创建二叉树
    private TreeNode creatBiTree(LinkedList<T> inputList){
        TreeNode<T> tmp = null;
        //判空
        if(inputList == null || inputList.isEmpty()){
            return null;
        }
        //存数
        T data = inputList.removeFirst();
        if(data != null){
            tmp = new TreeNode(data);
            tmp.leftChild = this.creatBiTree(inputList);
            tmp.rightChild = this.creatBiTree(inputList);
        }
        //返回根结点
        return tmp;
    }

    //前序遍历
    public void PreOrder(){
        System.out.println("前序遍历开始:");
        preOrder(this.node);
        System.out.println("前序遍历结束:");

    }
    //前序遍历  递归实现
    private void preOrder(TreeNode<T> node){
        if (node != null){
            System.out.println(node.data);
            preOrder(node.leftChild);
            preOrder(node.rightChild);
        }
    }

    //中序遍历
    public void InOrder(){
        System.out.println("中序遍历开始:");
        inOrder(this.node);
        System.out.println("中序遍历结束:");
    }
    //中序遍历 递归实现
    private void inOrder(TreeNode<T> node){
        if (node != null){
            inOrder(node.leftChild);
            System.out.println(node.data);
            inOrder(node.rightChild);
        }
    }
    //后序遍历
    public void PostOrder(){
        System.out.println("后序遍历开始:");
        postOrder(this.node);
        System.out.println("后序遍历结束:");
    }
    //后序遍历  递归实现
    private void postOrder(TreeNode<T> node){
        if (node != null){
            postOrder(node.leftChild);
            postOrder(node.rightChild);
            System.out.println(node.data);
        }
    }

    //层序遍历 非递归实现
    public void LerverOrder(){
        Queue<TreeNode> queue = new LinkedList<TreeNode>();
        //根节点入队
        queue.offer(node);
        System.out.println("层序遍历开始");
        while(!queue.isEmpty()){
            TreeNode<T> tmp = queue.poll();
            System.out.println(tmp.data);
            if(tmp.leftChild != null)
                queue.offer(tmp.leftChild);
            if(tmp.rightChild != null)
                queue.offer(tmp.rightChild);
        }
        System.out.println("层序遍历结束");
    }

}

NoReBiTree非递归实现类:

package com.dataStructure;

import sun.reflect.generics.tree.Tree;

import java.util.LinkedList;
import java.util.Stack;
/**
 * author zbl
 *
 * datetime 2019.11.266666
 *
 */
public class NoReBiTree<T> extends ReBiTree{

    //构造函数
    public NoReBiTree(LinkedList<T> inputList){
        super(inputList);
    }

    //前序遍历 非递归
    private void preOrder(TreeNode<T> node){
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode<T> tmp = this.node;
        while(tmp != null || !stack.isEmpty()){
            //迭代访问节点的左孩子,并入栈
            while(tmp != null){
                System.out.println(tmp.data);
                stack.push(tmp);
                tmp = tmp.leftChild;
            }
            //如果节点没有左孩子,则弹出栈顶,访问节点右孩子
            if(!stack.isEmpty()){
                tmp = stack.pop();
                tmp = tmp.rightChild;
            }
        }
    }

    //中序遍历 非递归
    private void inOrder(TreeNode<T> node){
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode<T> tmp = this.node;
        //当节点不为空,且栈不为空
        while(tmp != null || !stack.isEmpty()){
            //迭代访问节点的左孩子,并入栈
            while(tmp != null){
                stack.push(tmp);
                tmp = tmp.leftChild;
            }
            //访问叶子节点
            System.out.println(tmp.data);
            //栈非空,说明还未遍历完
            if(!stack.isEmpty()){
                //父节点出栈
                tmp = stack.pop();
                //访问父节点
                System.out.println(tmp.data);
                //访问右子树
                tmp = tmp.rightChild;
            }
        }
    }

    //后序遍历 非递归
    private void postOrder(TreeNode<T> node){
        Stack<TreeNode> stack = new Stack<TreeNode>();
        TreeNode<T> tmp = this.node;
        while(tmp != null || !stack.isEmpty()){
            while(tmp != null){
                stack.push(tmp);
                tmp = tmp.leftChild;
            }
            if(!stack.isEmpty()){
                tmp = stack.pop();
                //若为叶子节点,访问
                if(tmp.rightChild == null)
                    System.out.println(tmp.data);
                tmp = tmp.rightChild;
            }
        }
    }
}


TreeNode节点类:

package com.dataStructure;

/**
 * author zbl
 *
 * datetime 2019.11.266666
 *
 */
//结点类
public class TreeNode<T> {
    //指向下一个结点
    public TreeNode leftChild;
    public TreeNode rightChild;
    public T data;

    TreeNode(T data){
        this.data = data;
    }


}

Main主函数:

package com.dataStructure;

import java.util.LinkedList;
/**
 * author zbl
 *
 * datetime 2019.11.266666
 *
 */
public class Main {

    public static void main(String[] args) {
        LinkedList<Integer> linkedList = new LinkedList<Integer>();
        //二叉树值
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(4);
        linkedList.add(null);linkedList.add(null);
        linkedList.add(5);
        linkedList.add(null);linkedList.add(null);
        linkedList.add(3);
        linkedList.add(null);linkedList.add(6);


        ReBiTree<Integer> noReBiTree =  new ReBiTree<Integer>(linkedList);
        noReBiTree.PreOrder();
        noReBiTree.InOrder();
        noReBiTree.PostOrder();
        noReBiTree.LerverOrder();
    }
}

参考文献

王红梅,胡明,王涛编著. 数据结构(C++版)(第二版)[M]. 清华大学出版社.

魏梦舒(@程序员小灰)著. 漫画算法–小灰的算法之旅 [M]. 电子工业出版社.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值