• 【数据结构】树与二叉树


    目录

    树的定义

    二叉树的定义

    二叉树的性质

    满二叉树

    完全二叉树

    二叉树的存储结构

    顺序存储结构

    链式存储结构

    遍历二叉树(递归)

    二叉树的层次遍历

    先序创建二叉树

    复制二叉树

    销毁二叉树

    写在最后


    树的定义

    树是n个结点的有限集(n>=0)

    若n=0,则称为空树

    若n>0,则满足如下条件:

    1. 有且仅有一个特定的结点,称为根
    2. 其余结点可分为m个互不相交的有限集T1,T2,T3...Tm(m>=0),其中每个集合本身又是一棵树,称为根的子树

    树的一些基本术语
    根结点非空树中没有前驱结点的结点,例如A
    结点的度结点拥有的子树的个数,例如:A的度为3,B的度为2,H的度为0
    叶子/终端结点结点的度等于0,例如:K,L,H
    分支/非终端结点结点的度不等于0,例如:D
    树的度树内个结点的最大值,例如图示,树的度为3
    树的深度把上图的结点每一行记为一层,树的深度就是层数的最大值,在本例中就是4

    二叉树的定义

    二叉树是n(n>=0)个结点的有限集,不是树的特殊情况,两者是两个概念

    1. 当n等于0时是空集;
    2. 当n不等于0时,由一个根结点以及两个互不相交的左子树、右子树组成。

    如果二叉树有三个结点,则用二叉树和普通树分别表示为:

     

    二叉树的性质

    1. i 层中最多有 2i1" role="presentation">2i1 个结点,至少有 1 个结点。
    2. 深度为K的二叉树至多有 2k1" role="presentation">2k1 个结点,至少有 k 个结点。
    3. 对于一棵二叉树,叶子树为 n0" role="presentation">n0 ,度为2 的结点数为 n2" role="presentation">n2 ,那么 n0=n2+1" role="presentation">n0=n2+1

    满二叉树

    性质:

    1. 每一层的结点都是满的;
    2. 叶子结点均在最底层;
    3. 每个结点位置均有元素;
    4. 编号规则:自上而下,自左而右;

    完全二叉树

    具有n个结点的完全二叉树的深度为[log2n" role="presentation">log2n]+1( [x]表示不大于x的最大整数),在一个满二叉树中,从最后一个结点开始,连续去掉任意个结点,即是一个完全二叉树。

    性质:

    如果对一棵有n个结点的完全二叉树,则对任一结点i(1<=i<=n)有:

    1. 双亲结点:如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则双亲结点为 [ i2" role="presentation">i2];(向下取整)
    2. 左孩子:如果2i>n,则结点i为叶子结点;否则,其左孩子结点为2i;
    3. 右孩子:如果2i+1>n,则结点i无右孩子;否则,其右孩子是结点2i+1;

    二叉树的存储结构

    顺序存储结构

    缺点:会出现最坏的情况,深度为k的且只有k个结点的单只树需要长度为2k1" role="presentation">2k1的一维数组,空间浪费严重,比较适合满二叉树,和完全二叉树的情况

     

    链式存储结构

    头文件

    1. #include "Queue.h"
    2. #include "Stack.h"
    3. #include "define.h"
    4. #ifndef __BINARYTREE_H
    5. #define __BINARYTREE_H
    6. typedef char BitreeElemType;
    7. typedef struct __BiNode
    8. {
    9. BitreeElemType data;
    10. __BiNode *lchild, *rchild;
    11. }BiNode, *BiTree;
    12. void InOrder(BiTree T);
    13. void PreOrder(BiTree T);
    14. void PostOrder(BiTree T);
    15. void LevelOrer(BiTree T);
    16. void Copy(BiTree *Tnew, const BiTree T);
    17. void Destroy(BiTree *root);
    18. #endif

    二叉链表

    1. typedef char ElemType;
    2. typedef struct BiNode
    3. {
    4. ElemType data;
    5. struct BiNode *lchild, *rchild;//左孩子,右孩子指针
    6. } BiNode, *BiTree;

    遍历二叉树(递归)

    先序遍历中序遍历后序遍历
    若二叉树为空,则空操作

    访问根节点;

    先序遍历左子树;

    先序遍历右子树;

    中序遍历左子树;

    访问根节点;

    中序遍历右子树;

    后序遍历左子树;

    后序遍历右子树;

    访问根节点;

    遍历二叉表的三种方法

    • 先序遍历结果(根左右):A  B  D  G  C  E  H  F
    • 中序遍历结果(左根右):D  G  B  A  E  H  C  F
    • 后序遍历结果(左右根):G  D  B  H  E  F  C  A
    1. void InOrder(BiTree T)//中序
    2. {
    3. if (!T)
    4. return;
    5. InOrder(T->lchild);
    6. printf("%c ", T->data);
    7. InOrder(T->rchild);
    8. }
    9. void PreOrder(BiTree T) //先序
    10. {
    11. if (!T)
    12. return;
    13. printf("%c ", T->data);
    14. PreOrder(T->lchild);
    15. PreOrder(T->rchild);
    16. }
    17. void PostOrder(BiTree T) //后序
    18. {
    19. if (!T)
    20. return;
    21. PostOrder(T->lchild);
    22. PostOrder(T->rchild);
    23. printf("%c ", T->data);
    24. }

    二叉树的层次遍历

    使用队列(易理解):

    1. 将根结点进队
    2. 队不空时循环:从队列中出列一个结点*p访问它:                                                                            若它有左孩子,则将左孩子结点进队;                                                                                      若它有右孩子,则将右孩子结点进队;
    1. void LevelOrer(BiTree T)
    2. {
    3. BiTree temp = NULL;
    4. SqQueue Q;
    5. InitQueue(&Q);
    6. if (T) // 先入队根
    7. EntryQ(&Q, T);
    8. while (!IsEmpty(&Q))
    9. {
    10. OutQ(&Q, &temp); // temp暂存弹出值
    11. printf("%c", temp->data); //输出
    12. if (temp->lchild) //在入队temp的左孩子和右孩子
    13. EntryQ(&Q, temp->lchild);
    14. if (temp->rchild)
    15. EntryQ(&Q, temp->rchild);
    16. }
    17. }

    先序创建二叉树

    1. void Creat_BiTree_Pre(BiTree *T)
    2. {
    3. //根据输出字符识别虚空节点,'#' 代表虚空节点
    4. char e;
    5. scanf(" %c", &e); //输入字符
    6. if ( e== '#')
    7. *T = NULL; //设置虚空节点
    8. else
    9. {
    10. *T = (BiTree)malloc(sizeof(BiNode));
    11. (*T)->data = e; //生成根结点
    12. Creat_BiTree_Pre(&(*T)->lchild);//构造左子树
    13. Creat_BiTree_Pre(&(*T)->rchild);//构造右子树
    14. }
    15. }

    复制二叉树

    如果,是空树,递归结束;

    否则,复制新结点空间,复制根结点:

    •       递归复制左子树
    •       递归复制右子树
    1. void Copy(BiTree *Tnew, const BiTree T)
    2. {
    3. if (!T)//如果是空树则返回
    4. {
    5. *Tnew = NULL;
    6. return;
    7. }
    8. else
    9. {
    10. *Tnew = (BiTree)malloc(sizeof(BiNode));
    11. (*Tnew)->data = T->data;
    12. Copy(&(*Tnew)->lchild, T->lchild);
    13. Copy(&(*Tnew)->rchild, T->rchild);
    14. }
    15. }

    销毁二叉树

    1. //递归的方式
    2. void Destroy(BiTree *root)
    3. {
    4. //销毁操作必须按照后续遍历的顺序
    5. if (!(*root))
    6. return;
    7. else
    8. {
    9. Destroy(&(*root)->lchild);
    10. Destroy(&(*root)->rchild);
    11. free(*root);
    12. *root = NULL;
    13. }
    14. }

    写在最后

    👍🏻点赞,你的认可是我创作的动力!

    ⭐收藏,你的青睐是我努力的方向!

    ✏️评论,你的意见是我进步的财富!

  • 相关阅读:
    003.文件描述符、重定向
    C++ STL 概述_严丝合缝的合作者们
    简单但好用:4种Selenium截图方法了解一下!
    C专家编程 第10章 再论指针 10.7 使用指针创建和使用动态数组
    C#对SQLite的常用操作
    Conformer Encoder GPU 加速策略较全面汇总
    React的类式组件和函数式组件之间有什么区别?
    可视化大屏时代的到来:智慧城市管理的新思路
    Spring启动后进行一些初始化的方式汇总
    重点| 系统集成项目管理工程师考前50个知识点(2)
  • 原文地址:https://blog.csdn.net/m0_73222051/article/details/127935628