数据结构与算法学习笔记八-二叉树的顺序存储表示法和实现(C语言)

news2024/12/29 4:33:06

目录

前言

1.数组和结构体相关的一些知识

1.数组

2.结构体数组

3.递归遍历数组

2.二叉树的顺序存储表示法和实现

1.定义

2.初始化

3.先序遍历二叉树

4.中序遍历二叉树

5.后序遍历二叉树

6.完整代码


前言

        二叉树的非递归的表示和实现。

1.数组和结构体相关的一些知识

1.数组

        在C语言中,可以将数组作为参数传递给函数。当数组作为参数传递时,实际上传递给函数的是数组的地址,而不是数组的副本。这意味着,在函数内部对数组进行的修改会影响到原始数组。

        例如在下面的代码中,我们把数组名作为参数传递给modifyArray函数,在函数中修改数组的值,main函数打印原来的数组,会发现原来的数组也被修改。

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

void modifyArray(int *s,int size){
    for (int i = 0; i < size; i++) {
        s[i] = s[i] * 10;
    }
    printf("\n");
}

int main(int argc, const char *argv[]) {
    int arr[5] = {1,2,3,4,5};
    int length = sizeof(arr) / sizeof(arr[0]);
    printf("修改之前的数组:\n");
    for (int i =  0; i < length;i++) {
        printf("%d\t",arr[i]);
    }
    modifyArray(arr,length);
    printf("\n修改之前的数组:\n");
    for (int i =  0; i < length;i++) {
        printf("%d\t",arr[i]);
    }
    printf("\n");
    return 0;
}

        当然上述的函数我们还可以写成数组的形式。

void modifyArray(int s[],int size){
    for (int i = 0; i < size; i++) {
        s[i] = s[i] * 10;
    }
    printf("\n");
}

2.结构体数组

        在上述的代码中,我们使用数组操作基本数据类型非常的方便。当时当我们需要自定义数据类型的时候,上述的代码就不满足我们的需求了。例如我们需要表示学生数组的时候,因为每个学生都有自己的属性,姓名,年龄等等,这个时候我们就需要使用结构体数组。

        在数据结构中,我们有时候需要使用数组表示一些数据类型,因此有时候我们需要把数组声明为全局函数。代码实例如下:

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

// 学生结构体
typedef struct {
    char name[50]; // 姓名
    int age;       // 年龄
} Student;

int main() {
    // 创建一个包含3个学生对象的数组并初始化
    Student students[3] = {
        {"张三", 20},
        {"李四", 21},
        {"王五", 22}
    };

    // 输出学生信息
    printf("学生信息如下:\n");
    for (int i = 0; i < 3; i++) {
        printf("学生姓名:%s\n", students[i].name);
        printf("学生年龄:%d\n", students[i].age);
    }

    return 0;
}

3.递归遍历数组

        在我们使用数组表示二叉树的时候,需要递归遍历数组,这里需要您了解数组递归的写法。

        在这个示例中以下面的代码为例,,recursivePrint 函数用于递归地遍历数组并打印数组中的元素。它接受三个参数:arr 表示数组,size 表示数组的大小,index表示当前遍历的索引位置。函数首先检查索引是否超出数组范围,如果是,则递归终止。否则,它打印当前索引处的数组元素,然后递归调用自身,传入下一个索引位置。在 main函数中,我们创建一个数组并调recursivePrint 函数来遍历打印数组元素。

#include <stdio.h>

// 递归遍历数组并打印数组中的元素
void recursivePrint(int arr[], int size, int index) {
    // 递归终止条件:当索引超出数组范围时,结束递归
    if (index >= size) {
        return;
    }
    
    // 打印当前索引处的数组元素
    printf("%d ", arr[index]);
    
    // 递归调用,遍历下一个元素
    recursivePrint(arr, size, index + 1);
}

int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int size = sizeof(arr) / sizeof(arr[0]);
    
    printf("数组元素为:");
    recursivePrint(arr, size, 0);
    printf("\n");
    
    return 0;
}

2.二叉树的顺序存储表示法和实现

     图1.完全二叉树

               图2.普通二叉树

        我们使用一组连续的存储空间表示树的结构。按照从上到下、从左到右的顺序存储完全二叉树的的节点,对于一般二叉树上的点,我们使用0表示不存在该节点。

        对于图1来说,内存中的存储结构如下图3所示。

        图3.完全二叉树的存储结构

        如果不是二叉树,假如我们使用0表示结点不存在,图2所示的存储结构如图4所示。

图4.普通二叉树

        下面我们看看如果使用代码来实现。

1.定义

        我们使用数组实现二叉树的顺序存储

#define MAX_TREE_SIZE 100

typedef char TElemType;
typedef int Status;

typedef TElemType SqBiTree[MAX_TREE_SIZE];

2.初始化

        初始化时候,将数组中的元素全部设为"\0"

// 初始化二叉树
Status initSqBiTree(SqBiTree tree) {
    for (int i = 0; i< MAX_TREE_SIZE; i++) {
        tree[i] = '\0';
    }
    // 将二叉树所有元素初始化为空
    return 1; // 初始化成功
}

3.先序遍历二叉树

        遍历二叉树之前我们观察下根节点、左子树节点、右子树节点的规律。

        根节点的下标为a[0].左子树上的节点的下标依次为1,3,...2*i+1,右子树上的节点的下标依次为2,4,...2*i+2

// 前序遍历二叉树
void preOrderTraverse(SqBiTree tree, int node_index) {
    if (node_index < MAX_TREE_SIZE && tree[node_index] != '\0') {
        // 访问根节点
        printf("%c ", tree[node_index]);
        // 递归遍历左子树
        preOrderTraverse(tree, 2 * node_index + 1);
        // 递归遍历右子树
        preOrderTraverse(tree, 2 * node_index + 2);
    }
}

4.中序遍历二叉树

// 中序遍历二叉树
void inOrderTraverse(SqBiTree tree, int node_index) {
    if (node_index < MAX_TREE_SIZE && tree[node_index] != '\0') {
        // 递归遍历左子树
        inOrderTraverse(tree, 2 * node_index + 1);
        // 访问根节点
        printf("%c ", tree[node_index]);
        // 递归遍历右子树
        inOrderTraverse(tree, 2 * node_index + 2);
    }
}

5.后序遍历二叉树

// 后序遍历二叉树
void postOrderTraverse(SqBiTree tree, int node_index) {
    if (node_index < MAX_TREE_SIZE && tree[node_index] != '\0') {
        // 递归遍历左子树
        postOrderTraverse(tree, 2 * node_index + 1);
        // 递归遍历右子树
        postOrderTraverse(tree, 2 * node_index + 2);
        // 访问根节点
        printf("%c ", tree[node_index]);
    }
}

6.完整代码

#include <stdio.h>

#define MAX_TREE_SIZE 100

typedef char TElemType;
typedef int Status;

typedef TElemType SqBiTree[MAX_TREE_SIZE];

// 初始化二叉树
Status initSqBiTree(SqBiTree tree) {
    for (int i = 0; i< MAX_TREE_SIZE; i++) {
        tree[i] = '\0';
    }
    // 将二叉树所有元素初始化为空
    return 1; // 初始化成功
}

// 前序遍历二叉树
void preOrderTraverse(SqBiTree tree, int node_index) {
    if (node_index < MAX_TREE_SIZE && tree[node_index] != '\0') {
        // 访问根节点
        printf("%c ", tree[node_index]);
        // 递归遍历左子树
        preOrderTraverse(tree, 2 * node_index + 1);
        // 递归遍历右子树
        preOrderTraverse(tree, 2 * node_index + 2);
    }
}

// 中序遍历二叉树
void inOrderTraverse(SqBiTree tree, int node_index) {
    if (node_index < MAX_TREE_SIZE && tree[node_index] != '\0') {
        // 递归遍历左子树
        inOrderTraverse(tree, 2 * node_index + 1);
        // 访问根节点
        printf("%c ", tree[node_index]);
        // 递归遍历右子树
        inOrderTraverse(tree, 2 * node_index + 2);
    }
}

// 后序遍历二叉树
void postOrderTraverse(SqBiTree tree, int node_index) {
    if (node_index < MAX_TREE_SIZE && tree[node_index] != '\0') {
        // 递归遍历左子树
        postOrderTraverse(tree, 2 * node_index + 1);
        // 递归遍历右子树
        postOrderTraverse(tree, 2 * node_index + 2);
        // 访问根节点
        printf("%c ", tree[node_index]);
    }
}

int main(int argc, const char *argv[]) {
    SqBiTree tree;
    
    // 初始化二叉树
    initSqBiTree(tree);

    // 构造一个简单的二叉树,根节点为'A',左子树为'B',右子树为'C'
    tree[0] = 'A';
    tree[1] = 'B';
    tree[2] = 'C';
    tree[3] = 'D';
    tree[4] = 'E';
    tree[5] = '\0';
    tree[6] = '\0';
    // 输出初始化后的二叉树
    printf("前序遍历结果为:");
    preOrderTraverse(tree, 0);
    printf("\n");

    printf("中序遍历结果为:");
    inOrderTraverse(tree, 0);
    printf("\n");

    printf("后序遍历结果为:");
    postOrderTraverse(tree, 0);
    printf("\n");

    return 0;
}


// 后序遍历二叉树
void postOrderTraverse(SqBiTree tree, int node_index) {
    if (node_index < MAX_TREE_SIZE && tree[node_index] != '\0') {
        // 递归遍历左子树
        postOrderTraverse(tree, 2 * node_index + 1);
        // 递归遍历右子树
        postOrderTraverse(tree, 2 * node_index + 2);
        // 访问根节点
        printf("%c ", tree[node_index]);
    }
}

int main(int argc, const char *argv[]) {
    SqBiTree tree;
    
    // 初始化二叉树
    initSqBiTree(tree);

    // 构造一个简单的二叉树,根节点为'A',左子树为'B',右子树为'C'
    tree[0] = 'A';
    tree[1] = 'B';
    tree[2] = 'C';
    tree[3] = 'D';
    tree[4] = 'E';
    tree[5] = '\0';
    tree[6] = '\0';
    // 输出初始化后的二叉树
    printf("前序遍历结果为:");
    preOrderTraverse(tree, 0);
    printf("\n");

    printf("中序遍历结果为:");
    inOrderTraverse(tree, 0);
    printf("\n");

    printf("后序遍历结果为:");
    postOrderTraverse(tree, 0);
    printf("\n");

    return 0;
}

        在main函数中,我们构建了一个图2所示的二叉树,控制台打印信息如下:

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

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

相关文章

Ps 滤镜:蒙尘与划痕

Ps菜单&#xff1a;滤镜/杂色/蒙尘与划痕 Filter/Noise/Dust & Scratch 蒙尘与划痕 Dust & Scratch滤镜可用于修复图像中的小瑕疵、尘埃或划痕&#xff0c;特别适合用于清理扫描的照片或老照片中的损伤&#xff0c;以及其他因拍摄条件不理想或相机传感器上的尘埃所造成…

网络安全防护:抵御DDoS和CC攻击

在当今数字化时代&#xff0c;网络安全已成为任何组织或个人不可忽视的重要议题。DDoS&#xff08;分布式拒绝服务&#xff09;攻击和CC&#xff08;命令与控制&#xff09;攻击作为两种最为常见的网络攻击方式&#xff0c;给网络运营者和用户带来了巨大的威胁和影响。本文将介…

Acrobat Pro DC 2023 for Mac:PDF处理的终极解决方案

Acrobat Pro DC 2023 for Mac为Mac用户提供了PDF处理的终极解决方案。它具备强大的文档处理能力&#xff0c;无论是查看、编辑还是创建PDF文件&#xff0c;都能轻松胜任。在编辑功能方面&#xff0c;Acrobat Pro DC 2023支持对文本、图像进行精准的修改和调整&#xff0c;还能添…

回溯法、全排列、子集等

回溯法 感想&#xff1a;回溯算法本质是一个循环&#xff0c;有点像while循环 一些回溯法&#xff08;递归&#xff09;的经典应用 1.全排列 2.子集 其实上面两个点&#xff0c;也是对应着高中数学里面的“排列”与“组合” 1.全排列问题 给定一个集合S{a,b,c}&#xff0…

服务的war包已经丢在tomcat中但是还是没法访问,如何排查?

问题出现的现象是我已经将 XWiki 的 WAR 包放置在 Tomcat 的 webapps目录下但仍然无法访问&#xff0c;反思之后可以从下面以下几个方面来诊断和解决问题&#xff1a; 1. 确认 Tomcat 正在运行 首先&#xff0c;确保 Tomcat 服务正在正常运行。可以使用以下命令检查 Tomcat 的…

word转pdf的java实现(documents4j)

一、多余的话 java实现word转pdf可用的jar包不多&#xff0c;很多都是收费的。最近发现com.documents4j挺好用的&#xff0c;它支持在本机转换&#xff0c;也支持远程服务转换。但它依赖于微软的office。电脑需要安装office才能转换。鉴于没在linux中使用office&#xff0c;本…

字符以及字符串函数

字符以及字符串函数 求字符串长度strlen 长度不受限制的字符串函数strcpystrcatstrcmp 长度受限制的字符串函数strncpystrncatstrncmp 字符串查找strstrstrtok 错误信息报告strerror 字符分类函数字符转换函数tolowertoupper 内存操作函数memcpymemmovememcmpmemset 这篇文章注…

【算法】Dijkstra求最短路算法

TOP提示&#xff1a;Dijkstra算法只适用于不含负权边的情况 Dijkstra算法是一个基于贪心&#xff0c;广搜和动态规划 求图中某点到其他所有点的最短路径的算法 一、步骤 首先我们先总结Dijkstra算法的完整步骤 我们需要一个dis数组存储从起点到达其他节点的最短距离&…

【小迪安全2023】第62天:服务攻防-框架安全CVE复现SpringStrutsLaravelThinkPHP

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

【影片欣赏】【指环王】【魔戒:国王归来 The Lord of the Rings: The Return of the King】

往期魔戒博客见&#xff1a; 【影片欣赏】【指环王】【魔戒&#xff1a;护戒使者 The Lord of the Rings: The Fellowship of the Ring】 【影片欣赏】【指环王】【魔戒&#xff1a;双塔奇谋 The Lord of the Rings: The Two Towers】 2004年发行&#xff0c;Special Extend…

控制情绪是交易成功的根本?大错特错

布雷特斯坦伯格&#xff08;Brett Steenbarger&#xff09;是一位在美国享有盛誉的交易心理学专家&#xff0c;他曾在华尔街的多个顶尖培训中心担任交易员的心理指导。身为心理学教授兼高级交易员的布雷特在交易心理方面要比别人了解得多。而且小编觉得做一个成功的交易员只靠交…

[c++]多态的分析

多态详细解读 多态的概念多态的构成条件 接口继承和实现继承: 多态的原理:动态绑定和静态绑定 多继承中的虚函数表 多态的概念 -通俗的来说&#xff1a;当不同的对象去完成某同一行为时&#xff0c;会产生不同的状态。 多态的构成条件 必须通过基类的指针或者引用调用虚函数1虚…

KMeans,KNN,Mean-shift算法的学习

1.KMeans算法是什么&#xff1f; 在没有标准标签的情况下&#xff0c;以空间的k个节点为中心进行聚类&#xff0c;对最靠近他们的对象进行归类。 2.KMeans公式&#xff1a; 2. 1.关键分为三个部分&#xff1a; 1.一开始会定义n个中心点&#xff0c;然后计算各数据点与中心点…

重装前端整体流程

用户管理 --汇总 -- 明细-CSDN博客 一、node 这个看环境变量 2023最新版Node.js下载安装及环境配置教程&#xff08;非常详细&#xff09;从零基础入门到精通&#xff0c;看完这一篇就够了_nodejs安装及环境配置-CSDN博客 配置到国内镜像的时候&#xff0c;去看&#xff0c;淘…

05.线程

进程有哪些缺陷&#xff1f; 1.创建的代价较高 进程是OS进行资源分配的基本单位&#xff0c;也就是说创建进程是需要分配资源的&#xff0c;所以创建代价很高 2.通信不方便 进程之间要想进行通信必须借助第三方资源&#xff08;管道、内存映射、消息队列&#xff09; 线程的优…

在线教程|二次元的福音!一键部署APISR,动漫画质飞跃升级

从守护城市安全的「火眼金睛」&#xff0c;到探索人体奥秘的医学之窗&#xff0c;再到娱乐产业的视觉盛宴&#xff0c;乃至遥望宇宙的卫星视角&#xff0c;超分辨率技术重塑着我们观察世界的新维度&#xff0c;让每一寸画面绽放前所未有的清晰与真实。 近年来&#xff0c;越来…

【C++】C++中的template模板

一、泛型编程 关于模板的出现其实是在广大程序员编程中偷懒省下来的。我举个例子你们就知道了。 下述例子是用来实现swap函数的&#xff0c;利用的方式是最基础的重载。 void Swap(int& left, int& right) {int temp left;left right;right temp; } void Swap(d…

【Linux操作系统】:文件操作

目录 前言 一、C语言中文件IO操作 1.文件的打开方式 2.fopen&#xff1a;打开文件 3.fread&#xff1a;读文件 4.fwrite:写文件 二、系统文件I/O 1.系统调用open、read、write 2.文件描述符fd 3.文件描述符的分配规则 4.重定向 5.缓冲区 6.理解文件系统 磁盘 磁盘…

掌握这几点,稳稳拿下中质协六西格玛考试!

在当今竞争激烈的市场环境中&#xff0c;拥有六西格玛证书无疑是提升自身职业竞争力的一大利器。中质协作为权威机构&#xff0c;其六西格玛考试更是备受关注。那么&#xff0c;如何才能稳稳拿下这场考试呢&#xff1f;深圳天行健六西格玛管理培训公司有建议如下&#xff1a; 一…

【计算机毕业设计】springboot国风彩妆网站

二十一世纪我们的社会进入了信息时代&#xff0c; 信息管理系统的建立&#xff0c;大大提高了人们信息化水平。传统的管理方式对时间、地点的限制太多&#xff0c;而在线管理系统刚好能满足这些需求&#xff0c;在线管理系统突破了传统管理方式的局限性。于是本文针对这一需求设…