数据结构(5)树

一、树

        树型结构是一种一对多的结构,非线性的结构

二、树的基本要素

  1. 根节点(Root):树的顶层节点,没有父节点。
  2. 叶子节点(Leaf):没有子节点的节点。
  3. 子树(Subtree):树的某个节点及其所有后代节点构成的树。
  4. 深度(Height):树的高度是从根节点到最深叶子节点的最长路径上的边数。
  5. 深度(Depth):节点的深度是从根节点到该节点的路径上的边数。

三、二叉树

二叉树是一种特殊的树结构,每个节点最多有两个子节点,通常称为左子节点和右子节点。二叉树的基本概念包括:

  1. 节点数:二叉树的节点数可以是任意非负整数。
  2. 满二叉树(Full Binary Tree):每个节点要么是叶子节点,要么有两个子节点。
  3. 完全二叉树(Complete Binary Tree):除了最后一层外,所有层的节点都被完全填满,最后一层的节点尽可能靠左。
  4. 在一棵完全二叉树中,若有 𝑛n 个节点,则叶子节点的数量 𝐿L 可以通过以下公式计算:

𝐿=𝑛+1/2  = L=2n+1

  1. 非叶子节点数
    • 非叶子节点数 𝐼I 可以通过以下公式计算:𝐼=𝑛−𝐿  

满二叉树是指每个节点都有两个子节点的二叉树。对于满二叉树,节点个数与层数之间的关系可以用以下公式表示:

  1. 节点个数公式
    • 如果满二叉树的层数为 ℎh,则节点个数 𝑛n 的公式为:

𝑛=2ℎ−1n=2h−1

  • 其中,层数 ℎh 从 1 开始计数,根节点为第 1 层。
  1. 层数与节点个数的关系
    • 如果已知节点个数 𝑛n,可以通过以下公式计算出层数 ℎh:

ℎ=log⁡2(𝑛+1)h=log2​(n+1)

  1. 每层的节点个数
    • 在满二叉树中,第 𝑖i 层的节点个数为 2𝑖−12i−1(𝑖i 从 1 开始计数)。
#include <stdlib.h>  
#include <stdio.h>  

// 定义树节点的数据类型  
typedef char TDataType;  

// 定义二叉树节点结构体  
typedef struct TNode {  
    TDataType data;          // 节点存储的数据  
    struct TNode *pl;       // 指向左子节点的指针  
    struct TNode *pr;       // 指向右子节点的指针  
} TNode_t;  

// 预定义的树结构,'#' 表示空节点  
char tree[] = {"ABEH###G##CF#D##I##"};  
int idx = 0; // 用于遍历 tree 数组的索引  

// 创建二叉树的函数  
TNode_t *create_bin_tree() {  
    TDataType data = tree[idx++]; // 从 tree 数组中获取当前节点数据  
    if (data == '#') { // 如果数据是 '#',表示该节点为空  
        return NULL;  
    }  
    
    // 分配内存给新节点  
    TNode_t *pnode = malloc(sizeof(TNode_t));  
    if (NULL == pnode) { // 检查内存分配是否成功  
        perror("fail malloc");  
        return NULL;  
    }  
    pnode->data = data; // 设置节点数据  
    pnode->pl = create_bin_tree(); // 递归创建左子树  
    pnode->pr = create_bin_tree(); // 递归创建右子树  
    
    return pnode; // 返回创建的节点  
}  

// 前序遍历函数  
void pre_order(TNode_t *proot) {  
    if (NULL == proot) { // 如果当前节点为空,返回  
        return;  
    }  
    printf("%c", proot->data); // 访问根节点  
    pre_order(proot->pl); // 递归遍历左子树  
    pre_order(proot->pr); // 递归遍历右子树  
}  

// 中序遍历函数  
void mid_order(TNode_t *proot) {  
    if (NULL == proot) { // 如果当前节点为空,返回  
        return;  
    }  
    mid_order(proot->pl); // 递归遍历左子树  
    printf("%c", proot->data); // 访问根节点  
    mid_order(proot->pr); // 递归遍历右子树  
}  

// 后序遍历函数  
void pos_order(TNode_t *proot) {  
    if (NULL == proot) { // 如果当前节点为空,返回  
        return;  
    }  
    pos_order(proot->pl); // 递归遍历左子树  
    pos_order(proot->pr); // 递归遍历右子树  
    printf("%c", proot->data); // 访问根节点  
}  

// 计算树的节点总数  
int get_tree_node_cnt(TNode_t *proot) {  
    if (NULL == proot) { // 如果当前节点为空,返回 0  
        return 0;  
    }  
    // 递归计算左子树和右子树的节点数,加上当前节点  
    return get_tree_node_cnt(proot->pl) + get_tree_node_cnt(proot->pr) + 1;  
}  

// 计算树的层数  
int get_tree_layer_cnt(TNode_t *proot) {  
    if (NULL == proot) { // 如果当前节点为空,返回 0  
        return 0;  
    }  
    // 递归计算左子树和右子树的层数,取较大者加 1  
    int cntl = get_tree_layer_cnt(proot->pl);  
    int cntr = get_tree_layer_cnt(proot->pr);  
    return (cntl > cntr ? cntl : cntr) + 1;  
}  

// 销毁树的函数,释放节点内存  
void destroy_tree(TNode_t *proot) {  
    if (NULL == proot) { // 如果当前节点为空,返回  
        return;  
    }  
    destroy_tree(proot->pl); // 递归销毁左子树  
    destroy_tree(proot->pr); // 递归销毁右子树  
    free(proot); // 释放当前节点的内存  
}  

// 层序遍历函数(假设队列的实现已定义)  
void layer_order(TNode_t *proot) {  
    // 实现层序遍历的代码,使用队列  
}

 

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值