树和二叉树

简介: 树和二叉树

树和二叉树

文章目录

一、树型结构

1.1概念

树是一种非线性数据结构,是由n(n>=0)个有限节点组成的一个有层次关系的集合。把它叫做树是因为其形状长得像一棵倒挂的树,根在上,叶子在下。有以下特点:

  • 有一个特殊的节点,称为根节点,根没有前驱节点
  • 树是递归定义的
  • deeb20254d26e9039982721af702c9c8.png
  • 注意:在树形结构中,子树之间是不能有交集的,否则不能构成树形结构.

1.2树相关概念

  • 结点的度:一个结点含有子树的个数(简单可以理解为,每个结点向下的分支数);
  • 树的度:一棵树中,所有结点度的最大值;
  • 叶子结点(终端结点):度为0的结点;
  • 双亲结点(父节点):若一个结点含有子结点,则成这个结点为子结点的父结点;
  • 孩子结点(子结点):一个结点含有子树的根结点称为该结点的子节点(与双亲结点概念相似);
  • 根结点:一棵树中,没有双亲结点的结点;
  • 结点的层次:从根节点开始定义,根为第一层,根的子结点为第二层,以此类推;
  • 树的高度或深度:树中结点的最大层次;

二、二叉树

2.1概念

一棵二叉树是节点的一个有限集合,该集合:

  1. 或者为空
  2. 或者是由一个根节点加两棵称为左子树和右子树的二叉树组成。
  3. f93c6ea7dfb5856afbda165c1da5de13.png
  4. 二叉树不存在度大于2的结点
  5. 二叉树的子树左右次序不能调换,二叉树是有序树
  6. 二叉树可以只由左子树、右子树、根结点或者空树构成

2.2两种特殊的二叉树

  1. 满二叉树:一棵二叉树,如果每层的结点数达到最大值,则这棵二叉树称为满二叉树。一棵满二叉树的层数为k,总结点的个数为image.png
  2. 完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树引出来的。
  3. 34e3d577188540d2fc61cd1ec077de67.png

2.3二叉树的性质


若根结点所在的层数为1,则一棵二叉树第i层上最多有image.png个结点

若只有根结点的二叉树的深度为1,则深度为k的二叉树最大结点数位image.png

任何一棵二叉树, 如果其叶结点个数为image.png 度为2的非叶结点个数为image.png则有image.png

具有n个结点的完全二叉树的深度k为image.png上取整

对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i

的结点有:

若i>0,双亲序号:( i − 1 ) / 2 (i-1)/2(i−1)/2;i=0,i为根结点编号,无双亲结点

若2i+1<n,左孩子序号:2i+1,否则无左孩子

若2i+2<n,右孩子序号:2i+2,否则无右孩子

2.4二叉树的实现

二叉树的存储分为顺序存储类链表的链式存储

这里我们通过链式存储实现

 // 定义一个表示节点的类
     class TreeNode {
        int value; // 当前节点的值
        TreeNode left;  // 左子树的引用
        TreeNode right; // 右子树的引用
        // 构造方法
        public TreeNode(int value) {
            this.value = value;
        }
    }
// 根节点的引用
public TreeNode root;

2.5二叉树的操作

1.二叉树的创建

这里我们手动创建一个二叉树

    public void create() {
        // 先所有的节点创建出来
        TreeNode node1 = new TreeNode(1);
        TreeNode node2 = new TreeNode(2);
        TreeNode node3 = new TreeNode(3);
        TreeNode node4 = new TreeNode(4);
        TreeNode node5 = new TreeNode(5);
        TreeNode node6 = new TreeNode(6);
        TreeNode node7 = new TreeNode(7);
        TreeNode node8 = new TreeNode(8);
        // 处理引用关系
        node1.left = node2;
        node1.right = node3;
        node2.left = node4;
        node2.right = node5;
        node5.right = node8;
        node3.left = node6;
        node3.right = node7;
        // 指定根节点的引用
        root = node1;
    }

0303924226452ac54823f76c8b9ceaf9.png

2.二叉树的遍历

1.前中后序遍历

二叉树的遍历是指沿着某条搜索路线,对树中每个结点均做一次且只访问一次。

二叉树的遍历是最重要的基础操作之一,是二叉树的其他运算的基础

区别:

  1. 前序遍历:访问根结点–>根的左子树–>根的右子树(根–>左–>右)
  2. 中序遍历:左–>根–>右
  3. 后序遍历:左–>右–>根

根据二叉树的遍历还原二叉树

1.某完全二叉树按层次输出(同一层从左到右)的序列为 ABCDEFGH 。该完全二叉树的前序序列为()

A: ABDHECFG B: ABCDEFGH C: HDBEAFCG D: HDEBFGCA

2.二叉树的先序遍历和中序遍历如下:先序遍历:EFHIGJK;中序遍历:HFIEJKG.则二叉树根结点为()

A: E B: F C: G D: H

3.设一课二叉树的中序遍历序列:badce,后序遍历序列:bdeca,则二叉树前序遍历序列为()

A: adbce B: decab C: debac D: abcde

4.某二叉树的后序遍历序列与中序遍历序列相同,均为 ABCDEF ,则按层次输出(同一层从左到右)的序列为()

A: FEDCBA B: CBAFED C: DEFCBA D: ABCDEF

还原思路

d183842becf03065a32d244b2aa91774.png注意:当给出二叉树的前序和后序遍历时将无法还原二叉树

// 前序遍历
public void preOrder(TreeNode root) {
    if (root == null) {
        return;
    }
    System.out.print(root.value + " ");
    preOrder(root.left);
    preOrder(root.right);
}
// 中序遍历
public void inOrder(TreeNode root) {
    if (root == null) {
        return;
    }
    inOrder(root.left);
    System.out.print(root.value + " ");
    inOrder(root.right);
}
// 后序遍历
public void postOrder(TreeNode root) {
    if (root == null) {
        return;
    }
    inOrder(root.left);
    inOrder(root.right);
    System.out.print(root.value + " ");
}   

遍历的过程:

fafcd3f68d811c4fffbf0afd67e2eec4.png

2.层序遍历

层序遍历:简单来说就是从根结点所在的层数开始,从上到下,从左到右依次访问每个结

a4f704300b995cbf4340f605c8b55d32.png

实现代码

//层序遍历
public void levelOrder(TreeNode root) {
    if (root == null) {
        return;
    }
    //用队列辅助存放节点
    Queue<TreeNode> queue = new LinkedList<>();
    //存放头节点
    queue.offer(root);
    while (!queue.isEmpty()) {
        //出队一个元素
        TreeNode node = queue.poll();
        System.out.print(node.value + " ");
        if (node.left != null) {
            queue.offer(node.left);
        }
        if (node.right != null) {
            queue.offer(node.right);
        }
    }
    System.out.println();
}

3.二叉树的基本操作

1.获取树中结点的个数

/**
 * 获取树中节点的个数 - 子问题思路
 *
 * @param root
 * @return
 */
public int size(TreeNode root) {
    //判断是否为空
    if (root == null) {
        return 0;
    }
    return size(root.left) + size(root.right) + 1;
}
public int nodeSize;
/**
 * 获取树中节点的个数 - 遍历思路
 *
 * @param root
 * @return
 */
static int count = 0;
public int size1(TreeNode root) {
    if (root == null) {
        return 0;
    }
    count++;
    size1(root.left);
    size1(root.right);
    return count;
}

2.获取叶子结点个数

/**
 * 获取叶子节点的个数 - 子问题
 *
 * @param root
 * @return
 */
public int getLeafNodeCount(TreeNode root) {
    if (root == null) {
        return 0;
    } else if (root.left == null && root.right == null) {
        return 1;
    }
    return getLeafNodeCount(root.left) + getLeafNodeCount(root.right);
}
public int leafCount;
/**
 * 获取叶子节点的个数 - 遍历
 *
 * @param root
 * @return
 */
public int getLeafNodeCount1(TreeNode root) {
    if (root == null) {
        return 0;
    } else if (root.left == null && root.right == null) {
        return leafCount++;
    }
    getLeafNodeCount1(root.left);
    getLeafNodeCount1(root.right);
    return leafCount;
}

3.获取第k层结点的个数

public int getKLevelNodeCount(TreeNode root, int k) {
    if (root == null || k <= 0) {
        return 0;
    }
    if (k == 1) {
        return 1;
    }
    return getKLevelNodeCount(root.left, k - 1) + getKLevelNodeCount(root.right, k - 1);
}

4.获取二叉树的高度

public int getHeight(TreeNode root) {
    if (root == null) {
        return 0;
    }
    int leftHeight = getHeight(root.left);
    int rightHeight = getHeight(root.right);
    return Math.max(leftHeight, rightHeight) + 1;
}

5.检测值为value的元素是否存在

public TreeNode find(TreeNode root, int val) {
    if (root == null) {
        return null;
    }
    if (root.value == val) {
        return root;
    }
    TreeNode left = find(root.left, val);
    TreeNode right = find(root.right, val);
    if (left != null) {
        return left;
    }
    if (right != null) {
        return right;
    }
    return null;
}

6.判断一棵树是不是完全二叉树

public boolean isCompleteTree(TreeNode root) {
    if (root == null) {
        return true;
    }
    //用队列辅助存放节点
    Queue<TreeNode> queue = new LinkedList<>();
    //存放头节点
    queue.offer(root);
    while (!queue.isEmpty()) {
        //出队一个元素
        TreeNode node = queue.poll();
        if (node != null) {
            //节点不为空,所有元素都入队
            queue.offer(node.left);
            queue.offer(node.right);
        } else {
            //节点为空全部出队,遇到非空元素,返回false
            while (!queue.isEmpty()) {
                TreeNode checkNode = queue.poll();
                if (checkNode != null) {
                    return false;
                }
            }
        }
    }
    return true;
}

2.6二叉树相关练习

  1. 检查两颗树是否相同
  2. 另一颗树的子树
  3. 翻转二叉树
  4. 判断一颗二叉树是否是平衡二叉树
  5. 对称二叉树
  6. 二叉树遍历
  7. 二叉树的层序遍历
  8. 二叉树的最近公共祖先
  9. 从前序与中序遍历序列构造二叉树
  10. 从中序与后序遍历序列构造二叉树
  11. 根据二叉树创建字符串
目录
相关文章
树和二叉树(三)
树和二叉树(三)
|
6月前
|
存储
树与二叉树
树与二叉树
|
存储 算法 数据库管理
树和二叉树(二)
树和二叉树(二)
|
6月前
|
机器学习/深度学习 存储 算法
树【二叉树,红黑树,B树,B+树】
树【二叉树,红黑树,B树,B+树】
68 0
|
存储 人工智能 算法
树结构的讲解与二叉树的基本运用
树结构的讲解与二叉树的基本运用
|
存储 人工智能 BI
树和二叉树(一)
树和二叉树(一)
|
存储 机器学习/深度学习 算法
九、树和二叉树
九、树和二叉树
九、树和二叉树
|
存储 算法
九、树和二叉树2
九、树和二叉树
九、树和二叉树2
|
存储 机器学习/深度学习 索引