数据结构-6-二叉树

本文介绍了二叉树的概念,包括节点、根节点、子节点、叶子节点等概念,以及二叉树的高度、子树和森林。接着阐述了二叉树的常用方法,如深度优先遍历(前序、中序、后序)和广度优先遍历,查找和删除操作。最后,提供了相关示例来辅助理解。
摘要由CSDN通过智能技术生成

六、二叉树(Binary Tree)

1、概念

先看数组结构:可以通过下标访问元素,速度快,对于有序数组,还可以使用二分查找法,提高查询效率。但是如果检索具体的元素或插入元素(按照一定顺序),则会整体移动数组,效率较低。

再看链表结构:插入和删除元素效率较高。但是查找元素时,需要从头节点开始查找,效率较低。

树结构:将数组结构和链表结构结合,能提高添加和查找元素的效率。

        ⑴       -------------- 根节点
    ⑵      ⑶    -------------- 父节点
  ⑷  ⑸      ⑺  -------------- 叶子节点/子节点
⑻
  • 节点:树结构的每个元素被称之为节点
  • 根节点:最顶端的节点
  • 父节点:存在下级节点
  • 子节点:存在上级节点
  • 叶子节点:没有下级节点
  • 节点的权:节点值
  • 路径:从根节点到某个节点的路线
  • 层:纵向看,树结构可以分为多层
  • 高度:最大层数(最大深度)
  • 子树:多个子节点,可以视为局部的树结构
  • 森林:多个子树一起构成了森林

二叉树:每个节点最多有两个子节点,左子树和右子树的顺序不能任意颠倒。

满二叉树:所有的叶子节点都在最后一层,并且节点总数 = 2^层数 - 1

       ⑴
   ⑵     ⑶
 ⑷  ⑸  ⑹  ⑺

完全二叉树:所有的叶子节点都在最后一层或倒数第二层,并且除最后一层外,其它层符合满二叉树的规则

       ⑴
   ⑵     ⑶
 ⑷  ⑸  ⑹  ⑺
           ⑻ ⑼

2、常用方法

  1. 深度优先遍历

    • 前序遍历:父节点 — 左子树 — 右子数
    • 中序遍历:左子树 — 父节点 — 右子树
    • 后序遍历:左子树 — 右子树 — 父节点

    遍历方式和父节点的顺序有关

  2. 广度优先遍历:按照深度从浅到深,从左向右,依次添加子节点,并输出

  3. 查找:和遍历时的顺序是一致的

  4. 删除:先判断根节点,再依次判断左子节点(左叶子节点)和右子节点(右叶子节点)

    如果删除的是根节点/子节点,则对应的整个二叉树/子树会被删除

  5. 树的深度:取节点的左子树和右子树的深度最大的,并加1(当前节点的深度)

3、示例

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

class BinaryTree<T> {
   

    private TreeNode<T> root;

    public BinaryTree(TreeNode<T> root) {
   
        this.root = root;
    }

    /**
     * 前序遍历-迭代
     */
    public void preOrder() {
   
        if (null == root) {
   
            return;
        }

        // 栈-LIFO
        Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
        stack.push(root);
        while (!stack.isEmpty()) {
   
            TreeNode<T> node = stack.pop();
            System.out.print(node.getData() + " ");
            // 先入栈右节点
            TreeNode<T> rightNode = node.getRight();
            if (null != rightNode) {
   
                stack.push(rightNode);
            }
            // 再入栈左节点
            TreeNode<T> leftNode = node.getLeft();
            if (null != leftNode) {
   
                stack.push(leftNode);
            }
        }
        System.out.println();
    }

    /**
     * 中序遍历-迭代
     */
    public void infixOrder() {
   
        if (null == root) {
   
            return;
        }

        Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
        TreeNode<T> node = root;
        while (!stack.isEmpty() || null != node) {
   
            if (null != node) {
   
                stack.push(node); // 入栈父节点
                node = node.getLeft(); // 指向左节点
            } else {
   
                node = stack.pop(); // 出栈左节点
                System.out.print(node.getData() + " ");
                node = node.getRight(); // 指向右节点
            }
        }
        System.out.println();
    }

    /**
     * 后序遍历-迭代
     */
    public void postOrder() {
   
        if (null == root) {
   
            return;
        }

        Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();
        TreeNode<T> node = root;
        Map<T, Boolean> map = new HashMap<T, Boolean>();
        while (!stack.isEmpty() || null != node) {
   
            if (null != node) {
   
                stack.push(node); // 入栈父节点
                map.put(node.getData(), false); // 记录还未曾指向右节点
                node = node.getLeft(); // 指向左节点
            } else {
   
                node = stack.pop();
                if (map.get(node.getData())) {
    // 曾指向过右节点
                    System.out.print(node.getData() + " "
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值