浅谈二叉树的概述、创建、遍历(附java版本代码)

树结构

树结构定义

  • 树结构是一种非线性存储结构,能表示“一对多”的关系。

树结构特点

  • 只有一个节点的树也是树
  • 新节点与任何一个节点连接形成的树称为子树
  • 根节点,没有父亲节点,叶子节点没有子节点
  • 除根节点外,任何一个节点都只有一个父节点

二叉树结构

二叉树的定义

  • 每个节点最多有两个子节点的树称为二叉树
  • 一棵深度为k,且有2^k-1个节点的二叉树,称为满二叉树。这种树的特点是每一层上的节点数都是最大节点数。
  • 一棵二叉树中,除最后一层外,若其余层都是满的,并且最后一层或者是满的,或者是在右边缺少连续若干节点,则此二叉树为完全二叉树
  • 具有n个节点的完全二叉树的深度为floor(log2n)+1。深度为k的完全二叉树,至少有2k-1个叶子节点,至多有2k-1个节点。

二叉树的特点

  • 左子树都小于父节点,右子树都大于父节点
  • 左右子树分别是二叉排序树

二叉树的遍历

  • 前序遍历:根节点、左节点,右节点
  • 中序遍历:左节点,根节点,右节点
  • 后序遍历:左节点,有节点,根节点
  • 小技巧:
    所谓的序,其实就是从左往右,根节点的位置

二叉树

如图:

  • 前序遍历:10,5,3,8,9,12,11,14
  • 中序遍历:3,5,8,9,10,11,12,14
  • 后序遍历:10,5,3,8,9,12,11,14
  • 小技巧:
    前序 + 中序 => 后序 + 层序
    后序 + 中序 => 前序 + 层序

具体代码实现可访问仓库地址查看具体实现

重要的几个代码实现(java 版本):

  • 创建树
/**
     * 使用递归添加元素
     *
     * @param node
     * @param data
     * @return
     */
    private Node createTree(Node node, E data) {
        //数据不能为空
        if (Objects.isNull(data)) {
            return null;
        }
        //当当前节点为空时,添加元素,并且容量+1
        if (Objects.isNull(node)) {
            return new Node(data);
        }
        //元素比较,如果输入的元素比存在的小,往当前元素的左边继续查找。如果还是小,继续往左边查找。否则往右边查找。直到值为空。添加新的元素
        if (data.compareTo(node.data) < 0) {
            node.leftChild = createTree(node.leftChild, data);
        } else if (data.compareTo(node.data) > 0) {
            node.rightChild = createTree(node.rightChild, data);
        } else {//暂时不比较重复的元素
            logger.info("不能包含重复数据");
        }
        return node;
    }
  • 前序遍历
/**
     * 1.先放中节点
     * 2.有右节点放右节点
     * 3.有左节点放左节点
     *
     * @param currentNode
     * @return
     */
    public Collection<E> preOrder2(Node currentNode) {
        Collection<E> res = new ArrayList<E>();
        Stack<Node> stack = new Stack();
        stack.add(currentNode);
        //当前节点不等空,或者栈顶不为空,都需要继续遍历
        while (!stack.isEmpty()) {
            currentNode = stack.pop();
            res.add(currentNode.data);
            if (Objects.nonNull(currentNode.rightChild)) {
                stack.push(currentNode.rightChild);
            }
            if (Objects.nonNull(currentNode.leftChild)) {
                stack.push(currentNode.leftChild);
            }
        }
        return res;
    }
  • 中序遍历
 /**
     * 中序遍历方式2
     * // 1.左节点不为null则压入左节点
     * // 2.左节点为null时,pop并打印,左节点
     * // 3.在往右,右节点为null时,pop并打印
     * // 4.右节点不为null时,压入右节点
     *
     * @param currentNode
     * @return
     */
    public Collection<E> inOrder2(Node currentNode) {
        Collection<E> res = new ArrayList<E>();
        Stack<Node> stack = new Stack();
        //当前节点不等空,或者栈顶不为空,都需要继续遍历
        while (Objects.nonNull(currentNode) || !stack.isEmpty()) {
            if (Objects.nonNull(currentNode)) {
                stack.add(currentNode);
                currentNode = currentNode.leftChild;
            } else {
                currentNode = stack.pop();
                res.add(currentNode.data);
                currentNode = currentNode.rightChild;
            }
        }
        return res;
    }
  • 后序遍历
 /**
     * 非递归后序遍历,使用栈结构进行遍历
     * //和前序遍历一样的只不过是使用了两个栈
     * //在前序遍历的时候将 中 右 左 节点压栈
     * //在原来是打印的地方不打印,将本该打印的节点压到第二个栈中
     * //这样第二个栈的出栈顺序就是 右 左 中了
     * <p>
     * //
     * //         10       //
     * //      /     \     //
     * //     5      12    //
     * //    / \    /  \   //
     * //   3  8   11   14 //
     * //      \           //
     * //      9           //
     * //
     *
     * @param currentNode 需要遍历的节点
     * @return
     */
    public Collection<E> postOrder(Node currentNode) {
        Collection<E> res = new ArrayList<E>();
        Stack<Node> stack = new Stack();
        Stack<Node> resStack = new Stack();
        //把当前元素添加到栈低
        stack.push(currentNode);
        //当前节点不等空,或者栈顶不为空,都需要继续遍历
        while (!stack.isEmpty()) {
            currentNode = stack.pop();
            resStack.push(currentNode);
            if (Objects.nonNull(currentNode.leftChild)) {
                stack.push(currentNode.leftChild);
            }
            if (Objects.nonNull(currentNode.rightChild)) {
                stack.push(currentNode.rightChild);
            }
        }

        while (!resStack.isEmpty()) {
            res.add(resStack.pop().data);
        }

        return res;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值