【C语言】二叉树(BinaryTree)的创建、3种递归遍历、3种非递归遍历、结点度的实现

news2024/12/26 19:25:34

代码主要实现了以下功能:

  1. 二叉树相关数据结构定义
    定义了二叉树节点结构体 BiTNode,包含节点数据值(字符类型)以及指向左右子树的指针。
    定义了顺序栈结构体 SqStack,用于存储二叉树节点指针,实现非递归遍历。
  1. 二叉树的创建与遍历
    创建二叉树:通过 CreateBiTree 函数,根据输入的先序遍历字符序列(# 表示空节点),以递归方式创建二叉树。
    递归遍历:实现了二叉树的递归先序、中序、后序遍历函数,分别按照根 - 左 - 右、左 - 根 - 右、左 - 右 - 根的顺序输出节点字符序列。
    非递归遍历:借助栈实现了二叉树的非递归先序、中序、后序遍历函数,在遍历过程中除输出节点字符外,还输出节点进栈、出栈过程及栈顶节点字符。
  1. 二叉树相关应用实例
    统计节点度数:通过 TNodes 函数统计二叉树中度为 0、1、2 的节点个数。
    计算树的高度:利用 High 函数计算二叉树的高度。
    创建二叉排序树:通过 CreateBST 函数根据给定字符序列生成二叉排序树,并对创建的二叉树进行中序遍历及高度计算。
  1. 主函数功能整合
    在 main 函数中,依次调用上述函数完成以下操作:
    创建一棵二叉树并输出其递归和非递归的三种遍历结果及栈变化情况。
    统计该二叉树不同度数的节点个数。
    创建两棵二叉排序树并输出它们的中序遍历结果及高度。

祁许
为例

实现效果

祁许
祁许

完整代码

如下,注释详细

//
// Created by 13561 on 2024/11/28.
//

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define ERROR   0
#define TRUE    1
#define OK      1
#define MAXSIZE 100

typedef int Status;            //声明函数类型名
typedef  char TElemType;       //声明结点元素值的类型

//定义二叉树结点类型
typedef  struct BiTNode {

    TElemType  		data;
    struct BiTNode  *lchild, *rchild;  	    //指向左右孩子结点的指针

} BiTNode, *BiTree;

// 栈
typedef struct {
    BiTree data[MAXSIZE];
    int top;
}SqStack;



// 根据先序遍历的字符序列,创建一棵按二叉链表结构存储的二叉树,指针变量T指向二叉树的根节点
void CreateBiTree(BiTree *T) {

    TElemType ch;
    scanf(" %c",&ch);
    printf("Read character: %c\n", ch);

    // # 代表空结点
    if(ch == '#') {
        printf("#设置为空结点\n");
        *T = NULL;
    } else {

        *T = (BiTree)malloc(sizeof(BiTNode));
        if(!*T) {
            exit(0);
        }
        (*T)->data = ch;

        // 创建左、右子树
        CreateBiTree(&(*T)->lchild);
        CreateBiTree(&(*T)->rchild);
    }

}

// 递归先序遍历二叉树 T ,输出访问的结点字符序列
Status PreOrderTraverse(BiTree T) {
    // 根 - 左 - 右
    if(T) {
        printf("%c ",T->data);
        PreOrderTraverse(T->lchild);
        PreOrderTraverse(T->rchild);
    }
    return OK;
}

// 递归中序遍历二叉树 T ,输出访问的结点字符序列
Status InOrderTraverse(BiTree T) {
    // 左 - 根 - 右
    if(T) {
        InOrderTraverse(T->lchild);
        printf("%c ",T->data);
        InOrderTraverse(T->rchild);
    }
    return OK;
}

// 递归后序遍历二叉树 T ,输出访问的结点字符序列
Status PostOrderTraverse(BiTree T) {
    // 左 - 右 - 根
    if(T) {
        PostOrderTraverse(T->lchild);
        PostOrderTraverse(T->rchild);
        printf("%c ",T->data);
    }
    return OK;
}

// 栈基本操作
void InitStack(SqStack *S) {
    S->top = -1;
}

// 判断是否空
int StackEmpty(SqStack S) {
    return S.top == -1;
}

// 进栈
void Push(SqStack *S, BiTree e) {
    if (S->top == MAXSIZE - 1) {
        printf("栈满\n");
        return;
    }
    S->top++;
    S->data[S->top] = e;
}

// 出栈
BiTree Pop(SqStack *S) {
    if (StackEmpty(*S)) {
        printf("栈空\n");
        return NULL;
    }
    BiTree e = S->data[S->top];
    S->top--;
    return e;
}

BiTree GetTop(SqStack S) {
    if (StackEmpty(S)) {
        printf("栈空\n");
        return NULL;
    }
    return S.data[S.top];
}


// 非递归先序遍历二叉树 T,依靠栈实现
// 要求在遍历过程中输出访问的结点字符的同时,输出结点进栈/出栈的过程 和 栈中指针所指的结点字符
Status NRPreOrderTraverse(BiTree T) {
    SqStack S;
    InitStack(&S);
    if(T!=NULL) {
        BiTree p ;
        S.data[++(S.top)] = T;
        while(S.top != -1) {
            // 根节点出栈再找它的子树
            p = S.data[(S.top)--];
            printf("出栈 %c \n",p->data);
            // 右子树压在最底下
            if(p->rchild != NULL) {
                S.data[++(S.top)] = p->rchild;
            }
            if(p->lchild != NULL) {
                S.data[++(S.top)] = p->lchild;
            }
        }
    }
    return OK;
}

// 非递归中序遍历二叉树 T  左根右
Status NRInOrderTraverse(BiTree T) {
    SqStack S;
    InitStack(&S);
    BiTree p = T;
    while (p ||!StackEmpty(S)) {
        while (p) {
            //printf("结点 %c 准备进栈 \n", p->data);
            Push(&S, p);
            //printf("当前栈顶: %c \n", GetTop(S)->data);
            //printf("正在访问结点 %c \n", p->data);
            // 访问左边
            p = p->lchild;
        }
        // 栈不空就出栈
        if (!StackEmpty(S)) {
            p = Pop(&S);
            printf("结点 %c 出栈 \n", p->data);
            // 访问右边
            p = p->rchild;
        }
    }
    return OK;
}



// 非递归后序遍历二叉树 T  左右根
Status NRPostOrderTraverse(BiTree T) {
    SqStack S;
    InitStack(&S);
    BiTree p = T;
    BiTree lastVisited = NULL;
    while (p ||!StackEmpty(S)) {
        if(p) {
            S.data[++(S.top)] = p;
            // 访问左结点
            p = p->lchild;
        }
        else {
            p = S.data[S.top];
            // 不急着出栈左结点 看看右节点是否存在以及是否被访问过 压入栈中
            if (p->rchild != NULL && p->rchild != lastVisited) {
                p = p->rchild;
                S.data[++(S.top)] = p;
                // 查看右结点的左结点
                p = p ->lchild;
            }
            else {
                p = S.data[(S.top)--];
                printf("出栈 %c \n",p->data);
                lastVisited = p;
                // 在一个结点出栈后,紧接着下一个结点出栈,所以p直接置空
                p = NULL;
            }
        }
    }
    return OK;
}

// 应用实例1:返回二叉树T度分别为 0 , 1 , 2的结点数
void TNodes(BiTree T, int d, int *count) {
    if (T) {
        int degree = (T->lchild!= NULL) + (T->rchild!= NULL);
        if (degree == d) {
            (*count)++;
        }
        TNodes(T->lchild, d, count);
        TNodes(T->rchild, d, count);
    }
}

// 应用实例2:求二叉树 T 的高度
int High(BiTree T) {
    if (T == NULL) return 0;
    else {
        int leftHeight = High(T->lchild);
        int rightHeight = High(T->rchild);
        return (leftHeight > rightHeight)? (leftHeight + 1) : (rightHeight + 1);
    }
}

// 应用实例3:根据给定的字符序列生成二叉排序树
void CreateBST(BiTree *T, const char *chars) {
    *T = NULL;
    int len = strlen(chars);
    for (int i = 0; i < len; i++) {
        BiTree p = *T;
        BiTree q = NULL;
        while (p!= NULL) {
            q = p;
            if (chars[i] < p->data) {
                p = p->lchild;
            } else {
                p = p->rchild;
            }
        }
        BiTree newNode = (BiTree)malloc(sizeof(BiTNode));
        newNode->data = chars[i];
        newNode->lchild = newNode->rchild = NULL;
        if (q == NULL) {
            *T = newNode;
        } else if (chars[i] < q->data) {
            q->lchild = newNode;
        } else {
            q->rchild = newNode;
        }
    }
}


int main() {
    // (1) 调用CreateBiTree(T)函数生成一棵二叉树T
    BiTree T;
    printf("请输入二叉树T的先序遍历序列(#表示空节点):\n");
    CreateBiTree(&T);
    printf("先序遍历成功!\n");

    printf("------------------------------\n");


    // (2) 分别调用先序遍历、中序遍历和后序遍历的递归函数输出相应的遍历结果
    printf("递归先序遍历结果:\n");
    PreOrderTraverse(T);
    printf("\n");
    printf("递归中序遍历结果:\n");
    InOrderTraverse(T);
    printf("\n");
    printf("递归后序遍历结果:\n");
    PostOrderTraverse(T);
    printf("\n");

    printf("------------------------------\n");

    // (3) 分别调用先序遍历、中序遍历和后序遍历的非递归函数输出相应的遍历结果和栈元素的变化过程
    printf("非递归先序遍历结果及栈变化:\n");
    NRPreOrderTraverse(T);
    printf("------------------------------\n");
    printf("非递归中序遍历结果及栈变化:\n");
    NRInOrderTraverse(T);
    printf("------------------------------\n");
    printf("非递归后序遍历结果及栈变化:\n");
    NRPostOrderTraverse(T);
    printf("------------------------------\n");

    // (4) 调用TNodes(T)函数,输出二叉树T度分别为0、1、2的结点数
    int count0 = 0, count1 = 0, count2 = 0;
    TNodes(T, 0, &count0);
    TNodes(T, 1, &count1);
    TNodes(T, 2, &count2);
    printf("度为0的节点个数:%d\n", count0);
    printf("度为1的节点个数:%d\n", count1);
    printf("度为2的节点个数:%d\n", count2);

    printf("------------------------------\n");


    // (5) 调用CreateBST(T1,"DBFCAEG"),CreateBST(T2,"ABCDEFG"),创建两棵二叉树,对它们进行中序遍历,并调用High()函数输出其高度
    BiTree T1, T2;
    CreateBST(&T1, "DBFCAEG");
    CreateBST(&T2, "ABCDEFG");
    printf("T1中序遍历结果:");
    InOrderTraverse(T1);
    printf("\nT1高度:%d\n", High(T1));
    printf("T2中序遍历结果:");
    InOrderTraverse(T2);
    printf("\nT2高度:%d\n", High(T2));


    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2252049.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Three.js 和其他 WebGL 库 对比

在WebGL开发中&#xff0c;Three.js是一个非常流行的库&#xff0c;它简化了3D图形的创建和渲染过程。然而&#xff0c;市场上还有许多其他的WebGL库&#xff0c;如 Babylon.js、PlayCanvas、PIXI.js 和 Cesium&#xff0c;它们也有各自的特点和优势。本文将对Three.js 与这些常…

[pdf,epub]228页《分析模式》漫谈合集01-45提供下载

《分析模式》漫谈合集01-45的pdf、epub文件提供下载。已上传至本号的CSDN资源。 如果CSDN资源下载有问题&#xff0c;可到umlchina.com/url/ap.html。 已排版成适合手机阅读&#xff0c;pdf的排版更好一些。 ★UMLChina为什么叒要翻译《分析模式》&#xff1f; ★[缝合故事]…

CAD深度清理工具-AVappsDrawingPurge9.0.0(2024.8.27版本) 支持版本CAD2022-2025-供大家学习研究参考

图形文件DWG体积很大&#xff1a;通常没有明显的数据。同时&#xff0c;还其他症状包括&#xff1a; &#xff08;1&#xff09;无法复制和粘贴图元。 &#xff08;2&#xff09;悬挂较长时间选择文本与 “特性”选项板上打开。 &#xff08;3&#xff09;图形文件需要很长时间…

kafka数据在服务端时怎么写入的

学习背景 接着上篇&#xff0c;我们来聊聊kafka数据在服务端怎么写入的 服务端写入 在介绍服务端的写流程之前&#xff0c;我们先要理解服务端的几个角色之间的关系。 假设我们有一个由3个broker组成的kafka集群&#xff0c;我们在这个集群上创建一个topic叫做shitu-topic&…

Rook入门:打造云原生Ceph存储的全面学习路径(上)

文章目录 一.Rook简介二.Rook与Ceph架构2.1 Rook结构体系2.2 Rook包含组件2.3 Rook与kubernetes结合的架构图如下2.4 ceph特点2.5 ceph架构2.6 ceph组件 三.Rook部署Ceph集群3.1 部署条件3.2 获取rook最新版本3.3 rook资源文件目录结构3.4 部署Rook/CRD/Ceph集群3.5 查看rook部…

[STM32] ADC 模数转换器 (十)

文章目录 1.ADC概述1.1 转换模式&#xff08;规则组&#xff09;1.2 数据对齐1.3 转换时间1.4 校准 2.代码步骤 STM32F103C8T6的12位逐次逼近型ADC的工作原理&#xff0c;包括转换模式、数据对齐、转换时间、校准以及程序配置流程&#xff0c;同时涵盖了关键的库函数和中断管理…

Web3.0安全开发实践:代理合约最佳实践总结

代理模式使智能合约能够升级其逻辑&#xff0c;同时维持其链上地址和状态值。对代理合约的调用会通过delegateCall的方式执行来自逻辑合约的代码&#xff0c;以修改代理合约的状态。 本文将为大家概述代理合约的类型、相关的安全事件和建议&#xff0c;以及使用代理合约的最佳…

第29天 MCU入门

目录 MCU介绍 MCU的组成与作用 电子产品项目开发流程 硬件开发流程 常用元器件初步了解 硬件原理图与PCB板 常见电源符号和名称 电阻 电阻的分类 贴片电阻的封装说明&#xff1a; 色环电阻的计算 贴片电阻阻值计算 上拉电阻与下拉电阻 电容 电容的读数 二极管 LED 灯电路 钳位作…

【人工智能基础05】决策树模型

文章目录 一. 基础内容1. 决策树基本原理1.1. 定义1.2. 表示成条件概率 2. 决策树的训练算法2.1. 划分选择的算法信息增益&#xff08;ID3 算法&#xff09;信息增益比&#xff08;C4.5 算法&#xff09;基尼指数&#xff08;CART 算法&#xff09;举例说明&#xff1a;计算各个…

数据结构与算法(排序算法)

我本将心向明月&#xff0c;奈何明月照沟渠。 排序的概念 1. 排序是指将一组数据&#xff0c;按照特定的顺序进行排列的过程。 2. 这个过程通常是为了使数据更加有序&#xff0c;从而更容易进行搜索、比较或其他操作。 常见的排序算法 插入排序 1. 把待排序的记录&#xff0c…

思科实现网络地址转换(NAT)和访问控制列表(ACL)和动态路由配置并且区分静态路由和动态路由配置。

实验拓扑(分为静态路由和动态路由两种) 静态路由互通 动态路由互通 实验背景 这个是想实现外网与内网的连接跟网络的探讨&#xff0c;最终实现互通以及使用并且在网络地址转换后能使用网络然后再这个基础上再配置访问控制列表和网络地址转换的的学习过程。 实验需了解的知识…

开发一套ERP 第八弹 RUst 插入数据

更全面的报错,方便检查错误在哪里,现代高级语言越来越智能 还是得看下原文档怎么操作的 src 目录为crate 的根目录 想在crate 中模块相互引入需要在 main 中声明,各个模块,然后才能在各个模块中相互引入和使用 原始工程引入,避免直接使用 lib.rs 回合cargo 中的一些 工程管理出…

课程答疑微信小程序设计与实现

私信我获取源码和万字论文&#xff0c;制作不易&#xff0c;感谢点赞支持。 课程答疑微信小程序设计与实现 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了课程答疑微信小程序设计与实现的开发全过程。通过分析…

【时间之外】IT人求职和创业应知【53】-东莞也转型

目录 新闻一&#xff1a;Freysa挑战赛&#xff1a;人类智慧与策略战胜AI&#xff0c;奖金高达4.7万美元 新闻二&#xff1a;中国生成式AI用户规模突破2.3亿&#xff0c;行业应用广泛 新闻三&#xff1a;2024东莞智能终端新技术推广会圆满举行&#xff0c;聚焦AI与智能终端融…

ARP欺骗-监控网络

kali: 使用arp-scan -l 查看同个局域网 windows arp -a 查看地址的物理地址 192.168.21.2 对应的是00-50-56-f5-d5-f0 攻击利用: 我们要让目标ip的流量经过我的网卡,从网关出去 使用的开启 echo 1 > /proc/sys/net/ipv4/ip_forward 当为0时&#xff0c;我们不转发&…

Cesium 当前位置矩阵的获取

Cesium 位置矩阵的获取 在 3D 图形和地理信息系统&#xff08;GIS&#xff09;中&#xff0c;位置矩阵是将地理坐标&#xff08;如经纬度&#xff09;转换为世界坐标系的一种重要工具。Cesium 是一个强大的开源 JavaScript 库&#xff0c;用于创建 3D 地球和地图应用。在 Cesi…

网络编程项目1

基于TCP通信控制红色机械臂和蓝色机械臂的运作 1、项目要求&#xff1a;通过w&#xff08;红色臂角度增大&#xff09;s&#xff08;红色臂角度减小&#xff09;d&#xff08;蓝色臂角度增大&#xff09;a&#xff08;蓝色臂角度减小&#xff09; #include <myhead.h> #…

使用GitZip for github插件下载git仓库中的单个文件

背景&#xff1a;git仓库不知道抽什么疯&#xff0c;下载不了单个文件&#xff0c;点击下载没有反应&#xff0c;遂找寻其他方法&#xff0c;在这里简单记录下。 使用GitZip for github插件下载仓库中的单个文件 1、首先在浏览器安装插件&#xff0c;并确保为打开状态。 2、然…

Y20030022基于PHP+MYSQL疫苗预约管理网站的设计与实现 源码 初稿

旅游度假区微信小程序 1.摘要2.研究背景和意义3. 系统功能4.界面展示5.源码获取 1.摘要 疫苗预约管理系统是为了提供一个高效、便捷、安全的平台&#xff0c;方便用户进行疫苗预约接种&#xff0c;并优化疫苗接种的管理工作。通过该系统&#xff0c;用户可以随时随地进行预约操…

C#中判断两个 List<T> 的内容是否相等

ET实现游戏中邮件系统逻辑思路&#xff08;服务端&#xff09;_游戏邮件系统设计-CSDN博客 场景&#xff1a;今天遇到一个BUG&#xff0c;在服务器重启的时候&#xff08;体验服&#xff09;&#xff0c;玩家之前接收的邮件又重新接收了一次&#xff0c;但是两封邮件的ID是不同…