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

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

  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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【博主推荐】C# Winform 拼图小游戏源码详解(附源码)

文章目录 前言摘要1.设计来源拼图小游戏讲解1.1 拼图主界面设计1.2 一般难度拼图效果1.3 普通难度拼图效果1.4 困难难度拼图效果1.5 地域难度拼图效果1.6 内置五种拼图效果 2.效果和源码2.1 动态效果2.2 源代码 源码下载结束语 前言 在数字浪潮汹涌澎湃的时代&#xff0c;程序开…

C++初阶(十七)--STL--stack和queue详解及使用

目录 stack 概念 stack的定义 stack的使用 queue 概念 queue的定义 queue的使用 在 C 的标准模板库&#xff08;STL&#xff09;中&#xff0c;stack&#xff08;栈&#xff09;和queue&#xff08;队列&#xff09;是非常重要的容器适配器。它们基于其他基础容器实现&…

【ubuntu24.04】GTX4700 配置安装cuda

筛选显卡驱动显卡驱动 NVIDIA-Linux-x86_64-550.135.run 而后重启:最新的是12.6 用于ubuntu24.04 ,但是我的4700的显卡驱动要求12.4 cuda

远程桌面协助控制软件 RustDesk v1.3.3 多语言中文版

RustDesk 是一款开源的远程桌面软件&#xff0c;支持多平台操作&#xff0c;包括Windows、macOS、Linux、iOS、Android和Web。它提供端到端加密和基于角色的访问控制&#xff0c;确保安全性和隐私保护。使用简单&#xff0c;无需复杂配置&#xff0c;通过输入ID和密码即可快速连…

【Linux】gdb / cgdb 调试 + 进度条

&#x1f33b;个人主页&#xff1a;路飞雪吖~ &#x1f320;专栏&#xff1a;Linux 目录 一、Linux调试器-gdb &#x1f31f;开始使用 &#x1f320;小贴士&#xff1a; &#x1f31f;gdb指令 &#x1f320;小贴士&#xff1a; ✨watch 监视 ✨打条件断点 二、小程序----进…

C++初阶——动态内存管理

目录 1、C/C内存区域划分 2、C动态内存管理&#xff1a;malloc/calloc/realloc/free 3、C动态内存管理&#xff1a;new/delete 3.1 new/delete内置类型 3.2 new/delete自定义类型 4、operator new与operator delete函数 5、new和delete的实现原理 5.1 内置类型 5.2 自定…

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

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

【学习笔记】基于RTOS的设计中的堆栈溢出(Stack Overflow)-第1部分

本文由RTOS专家Jean J. Labrosse撰写。 基于RTOS的应用程序中的每个任务都需要自己的堆栈,堆栈的大小取决于任务的要求(例如,函数调用嵌套、传递给函数的参数、局部变量等)。 为了避免堆栈溢出,开发人员需要过度分配堆栈空间,但不要太多,以避免浪费RAM。 什么是堆栈溢…

基于java+SpringBoot+Vue的教学辅助平台设计与实现

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; Springboot mybatis Maven mysql5.7或8.0等等组成&#x…

mfc110u.dll是什么意思,mfc110u.dll丢失解决方法大全详解

mfc110u.dll是Microsoft Foundation Classes (MFC)库的一个特定版本&#xff08;版本11.0&#xff09;的Unicode动态链接库文件。MFC是Microsoft为C开发者设计的一个应用程序框架&#xff0c;主要用于简化Windows应用程序的开发工作。这个框架封装了很多Windows API函数&#x…

MySQL查看日志

目录 1. 日志 1.1 错误日志 1.2 二进制日志 1.2.1 介绍 1.2.2 格式 1.2.3 查看 1.2.4 删除 1.3 查询日志 1.4 慢查询日志 1. 日志 1.1 错误日志 错误日志是 MySQL 中最重要的日志之一&#xff0c;它记录了当 mysqld 启动和停止时&#xff0c;以及服务器在运行过…

API平台建设之路:从0到1的实践指南

在这个互联网蓬勃发展的时代&#xff0c;API已经成为连接各个系统、服务和应用的重要纽带。搭建一个优质的API平台不仅能为开发者提供便利&#xff0c;更能创造可观的商业价值。让我们一起探讨如何打造一个成功的API平台。 技术架构是API平台的根基。选择合适的技术栈对平台的…

【组件封装】uniapp vue3 封装一个自定义下拉刷新组件pullRefresh,带刷新时间和加载动画教程

文章目录 前言一、实现原理二、组件样式和功能设计三、scroll-view 自定义下拉刷新使用回顾相关属性&#xff1a;最终版完整代码&#xff1a; 前言 手把手教你封装一个移动端 自定义下拉刷新组件带更新时间和加载动画&#xff08;PullRefresh&#xff09;&#xff0c;以uniapp …

2、Three.js初步认识场景Scene、相机Camera、渲染器Renderer三要素

三要素之间关系&#xff1a; 有了虚拟场景Scene&#xff0c;相机录像Camera&#xff0c;在相机小屏幕上看到的Renderer Scene当前空间 Mesh人在场景 Camera相机录像 Renderer显示器上 首先先描述下Scene&#xff1a; 这个场景为三要素之一&#xff0c;一切需要展示的东西都需…

Unity中的数学应用 之 插值函数处理角色朝向 (初中难度 +Matlab)

CodeMonkey教程&#xff1a; https://www.youtube.com/watch?vQDWlGOocKm8 Siki学院汉化教程&#xff1a;如何使用Unity开发分手厨房&#xff08;胡闹厨房&#xff09;-Unity2023 - SiKi学院|SiKi学堂 - unity|u3d|虚幻|ue4/5|java|python|人工智能|视频教程|在线课程 版本&am…

2-2-18-7 QNX 系统架构-动态链接

阅读前言 本文以QNX系统官方的文档英文原版资料为参考&#xff0c;翻译和逐句校对后&#xff0c;对QNX操作系统的相关概念进行了深度整理&#xff0c;旨在帮助想要了解QNX的读者及开发者可以快速阅读&#xff0c;而不必查看晦涩难懂的英文原文&#xff0c;这些文章将会作为一个…

PPT不能编辑,按钮都是灰色,怎么办?

PPT文件打开之后&#xff0c;发现无法编辑&#xff0c;再仔细查看发现工具栏中的功能按钮都是灰色的&#xff0c;无法使用&#xff0c;这是什么原因&#xff1f;该如何解决&#xff1f; 原因&#xff1a;无法编辑PPT文件&#xff0c;并且功能按钮都是灰色&#xff0c;这是因为…

PMP–一、二、三模、冲刺–分类–8.质量管理

文章目录 技巧五、质量管理 一模8.质量管理--质量管理计划--质量管理计划包括项目采用的质量标准&#xff0c;到底有没有满足质量需求&#xff0c;看质量标准即可。6、 [单选] 自项目开始以来&#xff0c;作为项目经理同事的职能经理一直公开反对该项目&#xff0c;在讨论项目里…

深度学习中的生成对抗网络(GAN)原理与应用

引言 生成对抗网络&#xff08;Generative Adversarial Network&#xff0c;简称GAN&#xff09;是由Ian Goodfellow等人在2014年提出的一种深度学习模型&#xff0c;它通过对抗训练的方式生成与真实数据分布相似的假数据。GAN的出现极大地推动了深度学习和生成模型的研究&…

【CSS in Depth 2 精译_063】10.2 深入理解 CSS 容器查询中的容器

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 【第十章 CSS 容器查询】 ✔️ 10.1 容器查询的一个简单示例 10.1.1 容器尺寸查询的用法 10.2 深入理解容器 ✔️ 10.2.1 容器的类型 ✔️10.2.2 容器的名称 ✔️10.2.3 容器与模块化 CSS ✔️ 10.3…