• 树的基本概念及二叉树


    目录

    一、树的基本概念

    (1)树的结点

    (2)度

    (3)结点层次

    (4)树的高度 

    树的特点: 

    二、二叉树

    (1)满二叉树

    (2)完全二叉树 

    三、二叉树的存储 

    (1)顺序存储

    (2)链式存储 

    四、二叉树的遍历

    (1)前序遍历

    (2)中序遍历 

     (3)后序遍历

     (4)层序遍历


    树是一种非线性的数据结构,存储具有“一对多”关系特点元素的一种数据结构。例如:组织架构、图书目录、商品种类、热点搜索词等。

    如图所示就是一个 树 ,对数据A来说,和数据C、F有关系;对于数据F来说,和数据H、G有关系。这就是“一对多”的关系。 

    将具有“一对多”关系的集合中的数据元素按照树的形式进行存储,整个存储形状在逻辑结构上看,类似于实际生活中倒着的树,所以称这种数据的存储结构称为“树”。

    一、树的基本概念

    树是一种非线性的数据结构,包含n个结点的有限集合,结点之间具备一对多的逻辑关系,当树的结点n=0时,该树被称为空树。

    (1)树的结点

    树结构中,存储的每一个数据元素都被称为树的“结点”。

    结点又被细分为:根节点、子节点、叶子结点

     如图所示:叶子结点即树的末端结点,属于没有子结点的结点,统一称为叶子结点。

    子树:由某个子结点作为根结点组成的树被称为子树。上图中红色部分就是一个子树。

    (2)度

    对于一个结点,拥有的子树个数(结点有多少分支)称为结点的度

    树的度:一颗树的度是树内各结点的度的最大值。

    (3)结点层次

    从一棵树的根结点开始,根结点所在层为第一层,根结点的子结点所在层为第二层,依次类推

    (4)树的高度 

    一棵树的高度是树中结点所在的最大层次。树的高度,也被称为树的深度。

    树的特点: 

    在任意一个非空树中,有以下特点:

    1.有且仅有一个根结点

    2.一棵树中的任意两个结点,有且仅有唯一的一条路径连通,不存在回路。

    3.一棵树如果有n个结点,那么它一定有n-1条边

    二、二叉树

    二叉树是一种结点的度不大于2的有序树,子结点通常被称为“左孩子结点”和“右孩子结点”。

     如图所示就是一个二叉树

     这个图中树的度为3,所以此树就不是一个二叉树

    二叉树又被分为满二叉树完全二叉树 

    (1)满二叉树

    满二叉树是一种特殊的二叉树,它的所有非叶子节点都存在左右子结点,并且所有的叶子结点都在同一层级

    image.png

    满二叉树的特点:

    (2)完全二叉树 

    如果二叉树中,从根结点到倒数第二层,符合满二叉树要求,其叶子结点可以不完全填充,但必须靠从左到右连续分布,这样的二叉树被称为完全二叉树。

    image.png

    三、二叉树的存储 

    (1)顺序存储

    顺序存储指的是使用顺序表(数组)存储二叉树。但是顺序存储只适用于完全二叉树。满二叉树也是完全二叉树,所以同样适用。

    在顺序存储中,顺序表中的每一个位置仅存储结点的data,不需要存储左右子结点的指针,子结点的索引通过计算父结点下标完成。

    如果一个父结点的下标为parentIndex它的左结点下标为:2parentIndex,  右子结点下标为:2parentIndex+1

    如果完全二叉树,使用数组顺序存储,可以完全利用数组空间

    完全二叉树的顺序存储.png

    如果是普通二叉树,使用数组顺序存储,在数组中就会出现空隙,导致内存利用率降低

    二叉树的顺序存储.png

    1. //基于数组(顺序存储)的二叉树
    2. public class BinaryTree1<E> {
    3. // 创建一个新的空数组用来存储二叉树
    4. private Object[] elementData=null;
    5. // 进行初始化操作
    6. public BinaryTree1(E[] elements) {
    7. // 新数组的长度要比放入数据的数组长度大一个,因为新数组中从下标为1开始存储
    8. elementData=new Object[elements.length+1];
    9. for(int i=0,index=1;i<elements.length;i++,index++) {
    10. elementData[index]=elements[i];
    11. }
    12. }
    13. // 获取指定下标处的元素
    14. public E get(int index) {
    15. return (E) elementData[index];
    16. }
    17. // 获取指定下标的左孩子
    18. public E left(int index) throws Exception {
    19. // index<<12倍的index,一个子节点的下标的二倍是他的左孩子结点,如果2倍的index大于等于数组长度则没有左子孩子
    20. if((index<<1)>=elementData.length) {
    21. throw new Exception("没有左孩子");
    22. }
    23. return (E) elementData[index<<1];
    24. }
    25. // 获取指定下标的右孩子
    26. public E right(int index) throws Exception {
    27. if((index<<1)+1>=elementData.length) {
    28. throw new Exception("没有右孩子");
    29. }
    30. return (E) elementData[(index<<1)+1];
    31. }
    32. }

    (2)链式存储 

    二叉树的链式存储依靠指针将各个结点串联起来,不需要连续的存储空间。

    每个结点包括3个属性:

    • 数据 Data
    • 左孩子结点指针 Left
    • 右孩子结点 Right

    链式存储二叉树.png

    1. //二叉树的链式存储
    2. public class BinaryTree<E> {
    3. // 根节点
    4. TreeNode<E> root;
    5. public BinaryTree(E val) {
    6. root=new TreeNode<E>(val);
    7. }
    8. // 结点类
    9. static class TreeNode<E>{
    10. E data;
    11. TreeNode<E> left;
    12. TreeNode<E> right;
    13. public TreeNode() {
    14. }
    15. public TreeNode(E val) {
    16. this.data=val;
    17. }
    18. }
    19. public TreeNode<E> left(TreeNode<E> parent,E val){
    20. TreeNode<E> newNode=new TreeNode<E>(val);
    21. parent.left=newNode;
    22. return newNode;
    23. }
    24. public TreeNode<E> right(TreeNode<E> parent,E val){
    25. TreeNode<E> newNode=new TreeNode<E>(val);
    26. parent.right=newNode;
    27. return newNode;
    28. }
    29. }

    四、二叉树的遍历

    前序遍历根结点->左子树->右子树
    中序遍历左子树->根结点->右子树
    后序遍历左子树->右子树->根结点

    (1)前序遍历

    先序遍历.png

    1. public static void preOrder(TreeNode root) {
    2. if(root==null) {
    3. return;
    4. }
    5. System.out.print(root.data);
    6. preOrder(root.left);
    7. preOrder(root.right);
    8. }

    (2)中序遍历 

    中序遍历.png

    1. public static void inOrder(TreeNode root) {
    2. if(root==null) {
    3. return;
    4. }
    5. inOrder(root.left);
    6. System.out.print(root.data);
    7. inOrder(root.right);
    8. }

     (3)后序遍历

    后序遍历.png

    1. public static void postOrder(TreeNode root) {
    2. if(root==null) {
    3. return;
    4. }
    5. postOrder(root.left);
    6. postOrder(root.right);
    7. System.out.print(root.data);
    8. }

     (4)层序遍历

    层序遍历,就是按二叉树从上到下,从左到右,依次打印每层中每个结点存储的数据

    image.png

    1. public static void levelOrder(TreeNode root) {
    2. if(root==null) {
    3. return;
    4. }
    5. Queue<TreeNode> queue=new LinkedList<TreeNode>();
    6. queue.offer(root);
    7. while(true) {
    8. TreeNode t=queue.poll();
    9. if(t==null) {
    10. break;
    11. }
    12. //访问当前节点,就用打印表示访问即可
    13. System.out.print(t.data);
    14. if(t.left!=null) {
    15. queue.offer(t.left);
    16. }
    17. if(t.right!=null) {
    18. queue.offer(t.right);
    19. }
    20. }
    21. }

    五、二叉查找树

    二叉查找树也称为二叉排序树,即BST,是一种特殊的二叉树,它具备以下特点:

    1、若左子树不空,则左子树上所有结点的值均小于或等于它的根结点的值

    2、若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值。

    3、左、右子树也分为二叉排序树

    image.png

    二叉查找树的优势在于可以快速查找。 

    (1)二叉查找树的基本结构

    1. public class BST {
    2. // 根结点
    3. TreeNode root;
    4. // 树内部类
    5. static class TreeNode{
    6. Integer data;//结点数据
    7. TreeNode left;//左子结点
    8. TreeNode rigth;//右子结点
    9. TreeNode parent;//父结点
    10. public TreeNode() {
    11. }
    12. public TreeNode(Integer val) {
    13. this.data=val;
    14. }
    15. }
    16. }

    (2)插入结点实现

    1. // 插入新结点
    2. public void insert(TreeNode newNode) {
    3. // 默认使用根结点
    4. TreeNode currentNode=this.root;
    5. // 新结点的父结点
    6. TreeNode parentNode=null;
    7. // 查找新结点的父结点
    8. while(currentNode!=null) {
    9. parentNode=currentNode;
    10. if(newNode.data>currentNode.data) {
    11. //
    12. currentNode=currentNode.right;
    13. }else {
    14. //
    15. currentNode=currentNode.left;
    16. }
    17. }
    18. // 设置新结点的父结点
    19. newNode.parent=parentNode;
    20. // 判断当前树是否为空树
    21. if(parentNode==null) {
    22. this.root=newNode;
    23. }else {
    24. // 保存新结点
    25. if(parentNode.data<newNode.data) {
    26. parentNode.right=newNode;
    27. }else {
    28. parentNode.left=newNode;
    29. }
    30. }
    31. }

    (3)初始化BST

    1. public void init(int[] array) {
    2. for(int n:array) {
    3. insert(new TreeNode(n));
    4. }
    5. }

    (4)查找结点

    1. // 查找结点
    2. public TreeNode search(TreeNode parentNode,int data) {
    3. if(parentNode==null) {
    4. return parentNode;
    5. }
    6. if(data<parentNode.data) {
    7. return search(parentNode.left,data);
    8. }else if(data>parentNode.data){
    9. return search(parentNode.right,data);
    10. }else {
    11. return parentNode;
    12. }
    13. }

    (5)查找最大值

    1. // 查找最大值
    2. public TreeNode findMax(TreeNode currentNode) {
    3. if(currentNode==null) {
    4. return currentNode;
    5. }
    6. TreeNode parent=null;
    7. while(currentNode!=null) {
    8. parent=currentNode;
    9. currentNode=currentNode.rigth;
    10. }
    11. return parent;
    12. }

  • 相关阅读:
    SpringBoot项目调用Matlab方法
    九. Linux网络命令
    各种文件后缀的意义(持续更新中)
    Cascade-MVSNet论文笔记
    Android集成高德Flutter地图(一)基础地图显示
    ffmpeg 合并视频到一个画布
    [附源码]java毕业设计高校资源共享平台
    Nginx:动静分离(示意图+配置讲解)
    HTML+CSS网页设计期末课程大作业 【茶叶文化网站设计题材】web前端开发技术 web课程设计 网页规划与设计
    linux安装filebeat并收集日志到elasticsearch
  • 原文地址:https://blog.csdn.net/weixin_61430914/article/details/133642146