【数据结构】树和二叉树

树和二叉树

一. 树

树的定义(递归)

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

​ 若n=0,称为空树;

​ 若n>0,则满足以下两个条件:

​ (1)有且仅有一个 特定称为根的节点;

​ (2)其余节点 可分为m(m>=0)个互不相交的有限集T1,T2...,Tm ,其中每一个集合本身又是一棵树,并成为根的子树(SubTree)


2.

复制代码
  #### **树的基本术语**

  **根结点**:非空树中无前驱结点的结点。

  **结点的度**:结点拥有的子树数。

  **树的度**:树内各节点的度的最大值。

  **叶子(终端)结点**:度=0。

  **分支节点(非终端结点)** :度!=0。根结点以外的分支节点称为**内部结点**。

  **树的深度**:树中结点的最大层次。

  结点的子树的根称为该结点的孩子,该节点称为孩子的双亲。如果有共同的双亲,则互称为兄弟。位于同一层的结点为堂兄弟。结点的祖先:从根到该结点所经分支上的所有结点。

  结点的子孙:以某结点为根的子树中任意结点。

  ![image-20250302140633333](https://i-blog.csdnimg.cn/img_convert/2f35fc1b781eb199984b162cf6d377bd.png)

  **有序树**:树中结点的各子树从左到右有次序(最左边的为第一个孩子)。

  **无序树**:树中结点的各子树无次序。

  **森林**:是m(m\>=0)棵互不相交的树的集合。

  ​ 把根节点删除,树就变成了森林。

  ​ 一棵树可以看做一个特殊的森林。

  ### 二. 二叉树

  1.

     #### 二叉树的定义

     二叉树是n(n\>=0)个结点的有限集,它或者是空集,或者**由一个根结点及两颗互不相交的**分别称作这个根的左子树和右子树的二叉树组成。

     特点

     ​ 1、每个节点最多有两个孩子(**二叉树中不存在度大于2的结点**)。

     ​ 2、子树有左右之分,其次序不能颠倒。

     ​ 3、二叉树可以是空集合,根可以有空的左子树或空的右子树。
     > 二叉树不是树的特殊情况,他们是两个概念。
     >
     > 二叉树及时只有一棵树也必须进行区分为左子树还是右子树。

     ![image-20250302140700385](https://i-blog.csdnimg.cn/img_convert/72806c8608ef5bc0584ff96065649de1.png)

     ![image-20250226215933846](https://i-blog.csdnimg.cn/img_convert/b6f2f8a8ff24310b272f3a471a674541.png)
     2.

        #### **二叉树的性质和存储结构**

        ##### 2.1**性质**

        **性质1** :在二叉树的第i层上**至多** 有2^i-1^个结点(i\>=1)。![image-20250302140721031](https://i-blog.csdnimg.cn/img_convert/2af53c242891b74ef2704b35439968c5.png)

        **性质2** :深度为k的二叉树至多有2^k^-1个结点(k\>=1)。

        **性质3** :对任何一颗二叉树T,如果其叶子树为n~0~,度为2的结点数为n~2~,则**n~0~=n~2~+1**.
        * 两种特殊形式的二叉树

          编号:从上到下,从左到右

          1.满二叉树:一颗深度为k且有2^k^-1个结点的二叉树称为满二叉树

          2.完全二叉树:深度为k的有n个结点的二叉树,当且仅当其每一个结点都与深度为k的**满二叉树**中编号为1\~n的结点一一对应时,称为完全二叉树。

        完全二叉树的性质

        **性质4** :具有n个结点的完全二叉树深度为\[log~2~n\]+1.(\[x\]的意思是向下取整)

        **性质5**: 一棵有n个结点的完全二叉树,对任意结点i,有:如果i=1,则i为二叉树的根,如果i\>1,则其双亲结点是\[i/2\]

        ​ 如果2i\>n,则结点i为叶子结点,无左孩子;否则,其左孩子是结点2i

        ​ 如果2i+1\>n,则结点i无右孩子;否则,其右孩子结点为2i+1.

        ##### 2.2存储结构

        ###### 2.2.1 顺序存储结构

        ​ 实现: 按满二叉树的结点层次编号,依次存放二叉树中的数据元素.

        ​ 通过编码按顺序将二叉树中的元素存储进数组中.(二叉树中空结点依然要占据数组中的一个位置设为空)

        ​ 缺点: 容易浪费空间.

        ​ 特点: 适合于存满二叉树和完全二叉树

        ![image-20250302140739804](https://i-blog.csdnimg.cn/img_convert/68a1e189b0d4b4bee5521622f61ae2d6.png)

        ###### 2.2.2 链式存储结构

        ​ 实现: 通过指针,将各个地址的元素串联起来.

        ```c
        typedef struct biNode {
            int data;
            struct biNode *left;
            struct biNode *right;//指向左孩子和右孩子
        }biNode,*biTree;
        ```

​ 在n个结点的二叉链表中,有n+1个空指针域

遍历二叉树

3.1 遍历二叉树算法描述:

遍历方法: 依次遍历二叉树中的三个组成部分 L遍历左子树; D访问根结点; R遍历右子树. 则遍历整个二叉树的方案有:

DLR,LDR,LRD,DRL,RDL,RLD六种.

​ 若规定先左后右,则只有前三种情况:

DLR------先(根)序遍历 LDR------中(根序遍历) LRD------后(根)序遍历

​ 3.1.2 先序遍历:若二叉树为空,则进行空操作;否则 (1)访问根结点;(2)先序遍历左子树;(3)先序遍历右子树。

例:

​ 3.1.3 中序遍历:若二叉树为空,则空操作;否则(1)中序遍历左子树;(2)访问根结点;(3)中序遍历右子树。

例:

​ 3.1.4 后序遍历:若二叉树为空,则空操作;否则(1)后序遍历左子树;(2)后序遍历右子树;(3)访问根结点。

例:

3.2 二叉树的递归遍历

​ 3.2.1 先序递归遍历

c 复制代码
void preOrder(biTree T) {// 先序递归遍历二叉树
    if(T != NULL) {
        printf("%d ", T->data);//访问根结点
        preOrder(T->left);// 递归遍历左节点
        preOrder(T->right);// 递归遍历右节点
    }
}

​ 3.2.2 中序递归遍历

c 复制代码
void inOrder(biTree T) {// 先序递归遍历二叉树
    if(T != NULL) {
        inOrder(T->left);// 递归遍历左节点
        printf("%d ", T->data);//访问根结点
        inOrder(T->right);// 递归遍历右节点
    }
}

​ 3.2.3 后续递归遍历

c 复制代码
void postOrder(biTree T) {// 先序递归遍历二叉树
    if(T != NULL) {
        postOrder(T->left);// 递归遍历左节点
        postOrder(T->right);// 递归遍历右节点
        printf("%d ", T->data);//访问根结点
    }
}
3.3 中序遍历的非递归算法(栈)

基本思想:(1)建立一个栈;(2)根结点进栈,遍历左子树;(3)根节点出栈,输出根结点,遍历右子树。

c 复制代码
void inOrder2(biTree T) {
    initStack(S);//初始化栈
    biTree p = T;//p为用来遍历的指针
    while(p ||!=isEmpty) {
        // p或栈不为空时进循环
        if(p) {//向佐
            Push(S,p);//当前节点入栈
            p = p->left;//若左孩子不为空,则一直向左走
        }
        else {//出栈,并转向出栈节点的右孩子
            Pop(S,p);//栈顶元素出栈
            printf("%d ",p->data);//访问出栈节点
            p = p->right;//向右走
        }
    }
}
3.4 二叉树的层次遍历(队列)

概念:对于一颗二叉树,从根结点开始,按从上到下,从左到右的顺序访问每一个节点。每个节点仅访问一次。

基本思想:(1)将二叉树的根节点入队;

​ (2)若队列非空,则将队列头结点出队并访问该结点,若它有左孩子,则将其左孩子入队;若它有右孩子,则将其右孩子入队;

​ (3)重复(2),直至队列为空。

c 复制代码
void levelOrder(biTree T) {
    initQueue(Q);//初始化辅助队列
    biTree p;//p为用来遍历的指针
    enQueue(Q,T);//将根节点入队
    while(!isEmpty(Q)) {//若队列不空,则进入循环
        deQueue(Q,p);//队头节点出队
        printf("%d ",p->data);//访问出队节点
        if(p->left!=NULL) {
            enQueue(Q,p->left);//若左孩子不为空,则左孩子入队
        }
        if(p->right!=NULL) {//若右孩子不空,则右孩子入队
            enQueue(Q,p->right);
        }
    }
}	

图片源自:数据结构与算法

部分代码参考:CSDN

相关推荐
电星托马斯10 小时前
C++中顺序容器vector、list和deque的使用方法
linux·c语言·c++·windows·笔记·学习·程序人生
SsummerC10 小时前
【leetcode100】每日温度
数据结构·python·leetcode
jingshaoyou10 小时前
Strongswan linked_list_t链表 注释可独立运行测试
数据结构·链表·网络安全·list
逸狼14 小时前
【Java 优选算法】二分算法(下)
数据结构
march_birds16 小时前
FreeRTOS 与 RT-Thread 事件组对比分析
c语言·单片机·算法·系统架构
小麦嵌入式16 小时前
Linux驱动开发实战(十一):GPIO子系统深度解析与RGB LED驱动实践
linux·c语言·驱动开发·stm32·嵌入式硬件·物联网·ubuntu
云 无 心 以 出 岫17 小时前
贪心算法QwQ
数据结构·c++·算法·贪心算法
jelasin17 小时前
LibCoroutine开发手记:细粒度C语言协程库
c语言
篝火悟者17 小时前
自学-C语言-基础-数组、函数、指针、结构体和共同体、文件
c语言·开发语言
姜威鱼18 小时前
蓝桥杯python编程每日刷题 day 21
数据结构·算法·蓝桥杯