当前位置: 首页 > article >正文

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

http://www.kler.cn/a/418763.html

相关文章:

  • 认识redis 及 Ubuntu安装redis
  • Maya 中创建游戏角色的头发,并将其导出到 Unreal Engine 5
  • Mysql数据库基础篇笔记
  • 系统监控——分布式链路追踪系统
  • Java有关数组的相关问题
  • Flutter:页面滚动
  • Springboot集成通义大模型
  • 技术周总结 11.11~11.17 周日(Js JVM XML)
  • 动手学深度学习-2数据预处理、3线性代数
  • 梯度规约(gradient reduction)是什么?中英双语解释
  • 【热门主题】000071 大数据治理:开启数据价值新征程
  • 【力扣】387.字符串中的第一个唯一字符
  • VPC9527同步整流控制器,相对最大电压检测与强力自供电,与MP6908完全PIN TO PIN
  • Unity XR Interaction Toolkit 开发教程:手柄追踪【3.0以上版本】
  • MFC 实现按钮按下持续执行
  • Linux驱动开发第3步_INPUT子系统框架下的外部中断
  • HarmonyOS(61) 组件间状态共享的分类以及状态选择器的选取优先级
  • Android Glide批量加载Bitmap,拼接组装大Bitmap,更新单个AppCompatImageView,Kotlin(3)
  • 【element-tiptap】导出word
  • 在CentOS 7上设置Apache的mod_rewrite的方法
  • 【数据结构计数排序】计数排序
  • Java面经之JVM
  • Qt Sensors 传感器控制介绍篇
  • 【JAVA】IntelliJ IDEA 如何创建一个 Java 项目
  • Vue3+node.js实现注册
  • (免费送源码)计算机毕业设计原创定制:Apache+JSP+Ajax+Springboot+MySQL Springboot自习室在线预约系统