C语言之通讯录的实现篇优化版

目录

动态内存管理

通讯录声明

静态版本 

 动态版本

 ​初始化通讯录

静态版本

动态版本

Add增加通讯录

静态版本

动态版本

 Checkcapacity增容

DestroyContact释放动态空间 

文件操作

SaveContact保存信息到文件中 

初始化通讯录

旧版本

文件版本

LoadContact加载文件信息到通讯录

test.c

contact.h

contact.c


我们前面已经学习完 动态内存管理 和 C语言操作文件,相信你对内存的管理和操作有了更加深入的了解。那我们今天接着来优化一下前面我们写过的通讯录。

  • 特别提醒:函数如果放在后面,在使用函数前面必须声明!!

动态内存管理

使用动态内存相关的知识优化通讯录。主要是从增加内存的方面去优化。我们设置为以下规则,注意这种设置仅仅为了方便讲解和测试仅此而已。后期大家可以设置为自己想要的规则。

  • 通讯录刚刚开始可以存放3个人的信息。
  • 通讯录放满,可以增加容量,每次增加2个人的信息的空间。

通讯录声明

静态版本 

//通讯录---存放结构体的数组--每个结构体就是一个人的信息
typedef struct Contact
{PeoInfo data[MAX];//存放数据int sz;//记录当前通讯录中存放的人的信息个数
}Contact;

 动态版本

//动态版本
typedef struct Contact
{PeoInfo* data;//存放数据,可修改数组内存的空间了
//🆗PeoInfo结构体类型的指针int sz;//记录当前通讯录中存放的人的信息个数int capacity;//记录的是通讯录的当前容量
}Contact;
  • 当通讯录中存放的人的信息个数 sz == 通讯录当前容量 capacity就可以考虑增加容量问题。
  • 目前的data是没有空间的,需要在初始化的时候在堆区开辟3个人的信息空间。
  • PeoInfo* data  存放数据,可修改数组内存的空间了,🆗PeoInfo结构体类型的指针
  • PeoInfo* data  指针维护开辟的空间

 ​初始化通讯录

静态版本

void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;memset(pc->data, 0, sizeof(pc->data));
}

动态版本

#define DEFAULT_SZ 3 //后期容易修改
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(pc->capacity ,sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact->calloc");return;}
}
  •  PeoInfo* data  指针维护开辟的空间

Add增加通讯录

静态版本

void AddContact(Contact* pc)
{assert(pc);printf("请输入名字\n");scanf("%s", pc->data[pc->sz].name);//name是数组名,不用&printf("请输入年龄\n");scanf("%d", &(pc->data[pc->sz].age));//printf("请输入性别\n");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话\n");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址\n");scanf("%s", pc->data[pc->sz].addr);//pc->sz++;printf("增加成功\n");
}

动态版本

#define DEFAULT_INC 2//后期容易修改
//动态版本
void AddContact(Contact* pc)
{assert(pc);//满了增加容量if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));if (ptr != NULL){pc->data = ptr;}else{perror("AddContact->realloc");return;}}//不需要增容填写人信息printf("请输入名字\n");scanf("%s", pc->data[pc->sz].name);//name是数组名,不用&printf("请输入年龄\n");scanf("%d", &(pc->data[pc->sz].age));//printf("请输入性别\n");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话\n");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址\n");scanf("%s", pc->data[pc->sz].addr);//pc->sz++;printf("增加成功\n");
}
  • 当通讯录中存放的人的信息个数 sz == 通讯录当前容量 capacity就可以考虑增加容量问题。

当然也可以封装成函数Checkcapacity 

 Checkcapacity增容

Checkcapacity(pc);
void Checkcapacity(Contact* pc)
{if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + DEFAULT_INC) * sizeof(PeoInfo));if (ptr != NULL){pc->data = ptr;}else{perror("AddContact->realloc");return;}}
}

 当然我们使用了动态内存的空间,我们必须手动释放和销毁,我们封装一个函数去销毁。

DestroyContact释放动态空间 

void DestroyContact(Contact* pc);
case EXIT:DestroyContact(&con);printf("退出通讯录\n");break;
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;
}

文件操作

程序退出之后,输入的信息都丢了。所以在通讯录之前最好把我们输入的信息全部保存到文件里。

SaveContact保存信息到文件中 

//保存信息到文件
void SaveContact(Contact* pc);
case EXIT://保存通讯录中的数据到文件中SaveContact(&con);DestroyContact(&con);printf("退出通讯录\n");break;
void SaveContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "wb");//wb以二进制的方式写数据到文件if (pf == NULL){perror("SaveContact");return;}//写信息到文件int i = 0;//一个数据一个数据写for (i = 0; i < pc->sz; i++){fwrite(&(pc->data[i]), sizeof(PeoInfo), 1, pf);fwrite(pc->data+i, sizeof(PeoInfo), 1, pf);}//关闭文件fclose(pf);pf = NULL;
}
  • 字符以ASCII码和二进制的存储的方式相同
  • 整型以ASCII码和二进制的存储的方式不同

初始化通讯录

但是当程序再次跑起来的时候,还是看不到信息??所以我们需要在执行通讯录等一系列的功能之前我们就要从文件里读取到数据信息。我们去修改初始化部分

旧版本

void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(pc->capacity * sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact->calloc");return;}
}

文件版本

//文件版本
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(pc->capacity * sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact->calloc");return;}LoadContact(pc);
}

LoadContact加载文件信息到通讯录

//加载文件信息到通讯录
void LoadContact(Contact* pc);
void Checkcapacity(Contact* pc);//声明void LoadContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "rb");//以二进制的形式读if (pf == NULL){perror("LoadContact");return;}//读文件PeoInfo tmp = { 0 };//创建临时变量,结构体PeoInfo类型while (fread(&tmp, sizeof(PeoInfo), 1, pf))//读到就返回1,没有读到就返回0,一个一个读直到没有读到为0跳出循环{Checkcapacity(pc);//若文件中有5个人,但是这里只有3个人的容量,首先判断需不需要增容pc->data[pc->sz] = tmp;pc->sz++;}//关闭文件fclose(pf);pf = NULL;
}

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"
void menu()
{printf("************************************\n");printf("********1.add      2.del************\n");printf("********3.search   4.modify*********\n");printf("********5.show     6.sort***********\n");printf("********0.exit           ***********\n");printf("************************************\n");
}
enum Option
{EXIT,//0ADD,//1DEL,//2SEARCH,//3MODIFY,//4SHOW,//5SORT,//6	
};
int main()
{int input = 0;//创建通讯录Contact con;//初始化通讯录InitContact(&con);do{menu();printf("请输入你的选择:>\n");scanf("%d", &input);switch (input)//这里为了代码更加清晰用枚举常量{case ADD:AddContact(&con);break;case DEL:DelContact(&con);break;case SEARCH:SearchContact(&con);break;case MODIFY:ModifyContact(&con);break;case SHOW:ShowContact(&con);break;case SORT://SortContact(&con);break;case EXIT://保存通讯录中的数据到文件中SaveContact(&con);DestroyContact(&con);printf("退出通讯录\n");break;default:printf("选择错误,请重新选择:>\n");break;}} while (input);return 0;
}

contact.h

#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#define NAME_MAX 20
#define SEX_MAX 20
#define TELE_MAX 20
#define ADDR_MAX 30
#define MAX 100
#define DEFAULT_SZ 3
#define DEFAULT_INC 2
typedef struct PeoInfo
{char name[NAME_MAX];int age;char sex[SEX_MAX];char tele[TELE_MAX];char addr[ADDR_MAX];
}PeoInfo;//静态版本
//typedef struct Contact
//{
//	PeoInfo data[MAX];//存放数据
//	int sz;//记录当前通讯录中存放的人的信息个数
//}Contact;//动态版本
typedef struct Contact
{PeoInfo* data;//存放数据int sz;//记录当前通讯录中存放的人的信息个数int capacity;//记录的是通讯录的当前容量
}Contact;//初始化通讯录
void InitContact(Contact* pc);
//增加个人信息
void AddContact(Contact* pc);
//展示个人信息
void ShowContact(Contact* pc);
//删除个人信息
void DelContact(Contact *pc);
//查找个人信息
void SearchContact(Contact* pc);
//修改个人信息
void ModifyContact(Contact* pc);
//排序
//void SortContact(Contact* pc);
//释放空间
void DestroyContact(Contact* pc);
//保存信息到文件
void SaveContact(Contact* pc);
//加载文件信息到通讯录
void LoadContact(Contact* pc);

contact.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"contact.h"//初始化静态版本
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	memset(pc->data, 0, sizeof(pc->data));
//}//动态版本
//void InitContact(Contact* pc)
//{
//	assert(pc);
//	pc->sz = 0;
//	pc->capacity = DEFAULT_SZ;
//	pc->data = calloc(pc->capacity * sizeof(PeoInfo));
//	if (pc->data == NULL)
//	{
//		perror("InitContact->calloc");
//		return;
//	}
//}//文件版本
void Checkcapacity(Contact* pc);//声明
void LoadContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "rb");//以二进制的形式读if (pf == NULL){perror("LoadContact");return;}//读文件PeoInfo tmp = { 0 };while (fread(&tmp, sizeof(PeoInfo), 1, pf)){Checkcapacity(pc);pc->data[pc->sz] = tmp;pc->sz++;}//关闭文件fclose(pf);pf = NULL;
}
void InitContact(Contact* pc)
{assert(pc);pc->sz = 0;pc->capacity = DEFAULT_SZ;pc->data = calloc(pc->capacity * sizeof(PeoInfo));if (pc->data == NULL){perror("InitContact->calloc");return;}LoadContact(pc);
}//增加静态版本
//void AddContact(Contact* pc)
//{
//	assert(pc);
//	printf("请输入名字\n");
//	scanf("%s", pc->data[pc->sz].name);//name是数组名,不用&
//	printf("请输入年龄\n");
//	scanf("%d", &(pc->data[pc->sz].age));//
//	printf("请输入性别\n");
//	scanf("%s", pc->data[pc->sz].sex);
//	printf("请输入电话\n");
//	scanf("%s", pc->data[pc->sz].tele);
//	printf("请输入地址\n");
//	scanf("%s", pc->data[pc->sz].addr);
//	//
//	pc->sz++;
//	printf("增加成功\n");
//}//动态版本
void Checkcapacity(Contact* pc)
{if (pc->sz == pc->capacity){PeoInfo* ptr = (PeoInfo*)realloc(pc->data, (pc->capacity + 2) * sizeof(PeoInfo));if (ptr != NULL){pc->data = ptr;}else{perror("AddContact->realloc");return;}}
}void AddContact(Contact* pc)
{assert(pc);//满了增加容量Checkcapacity(pc);//不需要增容填写人信息printf("请输入名字\n");scanf("%s", pc->data[pc->sz].name);//name是数组名,不用&printf("请输入年龄\n");scanf("%d", &(pc->data[pc->sz].age));//printf("请输入性别\n");scanf("%s", pc->data[pc->sz].sex);printf("请输入电话\n");scanf("%s", pc->data[pc->sz].tele);printf("请输入地址\n");scanf("%s", pc->data[pc->sz].addr);//pc->sz++;printf("增加成功\n");
}//展示
void ShowContact(const Contact* pc)
{assert(pc);if (pc->sz == 0){printf("通讯录为空,无需打印\n");return 0;}int i = 0;//名字 年龄 性别 电话 地址//-左对齐//20是需要20字符的位置来放名字 printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");for (i = 0; i < pc->sz; i++){printf("%-20s%-5d%-5s%-12s%-30s\n",pc->data[i].name, pc->data[i].age, pc->data[i].sex, pc->data[i].tele, pc->data[i].addr);}
}//删除,查找,修改都需要使用
int FindByName(const Contact* pc, char name[])
{assert(pc);int i = 0;for (i = 0; i < pc->sz; i++){if (strcmp(pc->data[i].name, name) == 0){return i;}}return -1;
}//删除
void DelContact(Contact* pc)
{char name[NAME_MAX];//assert(pc);if (pc->sz == 0){printf("通讯录为空,无法删除\n");return;}printf("输入要删除的名字:>");scanf("%s", name);int ret = FindByName(pc, name);if (ret == -1){printf("要删除的人不存在\n");return;}//存在返回这个人的所在data的下标放入retint i = 0;for (i = ret; i < pc -> sz - 1; i++){pc->data[i] = pc->data[i + 1];}pc->sz--;printf("删除成功\n");
}//查找
void SearchContact(Contact* pc)
{char name[NAME_MAX];assert(pc);if (pc->sz == 0){printf("通讯录为空,无法查找\n");return;}//查找printf("输入要查找的名字:>");scanf("%s", name);int ret = FindByName(pc, name);if (ret == -1){printf("要查找的人不存在\n");return;}//返回下标显示这个的信息🆗printf("%-20s%-5s%-5s%-12s%-30s\n", "姓名", "年龄", "性别", "电话", "地址");printf("%-20s%-5d%-5s%-12s%-30s\n",pc->data[ret].name, pc->data[ret].age, pc->data[ret].sex, pc->data[ret].tele, pc->data[ret].addr);
}//修改
void ModifyContact(Contact* pc)
{char name[NAME_MAX];assert(pc);if (pc->sz == 0){printf("通讯录为空,无法修改\n");return;}//查找printf("输入要修改的名字:>");scanf("%s", name);int ret = FindByName(pc, name);if (ret == -1){printf("要修改的人不存在\n");return;}//修改assert(pc);printf("请输入名字\n");scanf("%s", pc->data[ret].name);//name是数组名,不用&printf("请输入年龄\n");scanf("%d", &(pc->data[ret].age));//printf("请输入性别\n");scanf("%s", pc->data[ret].sex);printf("请输入电话\n");scanf("%s", pc->data[ret].tele);printf("请输入地址\n");scanf("%s", pc->data[ret].addr);printf("修改成功\n");
}//释放动态空间
void DestroyContact(Contact* pc)
{free(pc->data);pc->data = NULL;pc->sz = 0;pc->capacity = 0;
}//写函数到文件中
void SaveContact(Contact* pc)
{//打开文件FILE* pf = fopen("contact.txt", "wb");//wb以二进制的方式写数据到文件if (pf == NULL){perror("SaveContact");return;}//写信息到文件int i = 0;//一个数据一个数据写for (i = 0; i < pc->sz; i++){fwrite(&(pc->data[i]), sizeof(PeoInfo), 1, pf);fwrite(pc->data+i, sizeof(PeoInfo), 1, pf);}//关闭文件fclose(pf);pf = NULL;
}

✔✔✔✔✔最后,感谢大家的阅读,若有错误和不足,欢迎指正!

接下来的博文会更新一些练习题,到实践中去加深对知识的理解。C语言的基本学习就快结束了,还是要多加练习。🆗

代码----------→【gitee:唐棣棣 (TSQXG) - Gitee.com】

联系----------→ 【邮箱:2784139418@qq.com】

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

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

相关文章

Openssl数据安全传输平台008:业务数据分析+工厂方法

文章目录 UML图1.1 客户端1.2 服务器端 UML图 1.1 客户端 // 准备要发送的数据 struct RequestMsg {//1 密钥协商 //2 密钥校验; // 3 密钥注销int cmdType; // 报文类型string clientId; // 客户端编号string serverId; // 服务器端编号string sign;string data; };1.2 服务器…

Unity之ShaderGraph如何实现UV抖动

前言 今天我们通过噪波图来实现一个UV抖动的效果。 如下图所示&#xff1a; 关键节点 Time&#xff1a;提供对着色器中各种时间参数的访问 UV&#xff1a;提供对网格顶点或片段的UV坐标的访问。可以使用通道下拉参数选择输出值的坐标通道。 SimpleNoise&#xff1a;根据…

Windows Server 2019 搭建FTP站点

目录 1.添加IIS及FTP服务角色 2.创建FTP账户&#xff08;用户名和密码&#xff09;和组 3.设置共享文件夹的权限 4.添加及设置FTP站点 5.配置FTP防火墙支持 6.配置安全组策略 7.客户端测试 踩过的坑说明&#xff1a; 1.添加IIS及FTP服务角色 a.选择【开始】→【服务器…

电流监测芯片SGM8199A2应用电路设计

SGM8199是一系列具有电压输出功能的双向电流监测芯片&#xff0c;用于监测共模电压范围内分流电阻上的压降&#xff0c;而不受电源电压的影响。该器件具有-0.1V至26V的宽共模电压范围输入。低偏移使得在监测电流时允许分流器上的满量程最大压降为10mV。SGM8199系列提供三种固定…

关于vant 的tabbar功能

1、想要实现tabbar页面A&#xff0c;其他的页面B&#xff08;非tabbar页面&#xff09;。 从A页面进入B页面&#xff0c;底部的active选中效果应该被取消掉&#xff0c;但是还是选中A。 按照官网的说法有两个方法 一、根据path路径 二、自定义的model 但是&#xff01;但是…

贪吃蛇项目实践

游戏背景&#xff1a; 贪吃蛇是久负盛名的游戏&#xff0c;它也和俄罗斯⽅块&#xff0c;扫雷等游戏位列经典游戏的⾏列。 实现基本的功能&#xff1a; 贪吃蛇地图绘制 蛇吃⻝物的功能 &#xff08;上、下、左、右⽅向键控制蛇的动作&#xff09; 蛇撞墙死亡 蛇撞⾃⾝死亡 计…

rust学习——栈、堆、所有权

文章目录 栈、堆、所有权栈(Stack)与堆(Heap)栈堆性能区别所有权与堆栈 所有权原则变量作用域所有权与函数返回值与作用域 栈、堆、所有权 栈(Stack)与堆(Heap) 栈和堆是编程语言最核心的数据结构&#xff0c;但是在很多语言中&#xff0c;你并不需要深入了解栈与堆。 但对于…

中间件安全-CVE复现WeblogicJenkinsGlassFish漏洞复现

目录 服务攻防-中间件安全&CVE复现&Weblogic&Jenkins&GlassFish漏洞复现中间件-Weblogic安全问题漏洞复现CVE_2017_3506漏洞复现 中间件-JBoos安全问题漏洞复现CVE-2017-12149漏洞复现CVE-2017-7504漏洞复现 中间件-Jenkins安全问题漏洞复现CVE-2017-1000353漏…

idea设置字体大小快捷键 Ctrl+鼠标上下滑 字体快捷键缩放设置

双击 按住ctrl鼠标滑轮上划放大就好了 这个双击设置为&#xff0c;Ctrl鼠标下滑 字体缩小就好了

手把手创建属于自己的ASP.NET Croe Web API项目

第一步&#xff1a;创建项目的时候选择ASP.NET Croe Web API 点击下一步&#xff0c;然后配置&#xff1a; 下一步&#xff1a;

Adobe Photoshop 基本操作

PS快捷键 图层 选择图层 Ctrl T&#xff1a;可以对图层的大小和位置进行调整 填充图层 MAC: AltBackspace (前景) or CtrlBackspace (背景) WINDOWS: AltDelete (前景) or CtrlDelete (背景) 快速将图层填充为前景色或背景色 平面化图层&#xff08;盖印图层&#xff09…

性能测试LoadRunner02

本篇主要讲&#xff1a;通过Controller设计简单的测试场景&#xff0c;可以简单的分析性能测试报告。 Controller 设计场景 Controller打开方式 1&#xff09;通过VUG打开 2&#xff09;之间双击Controller 不演示了&#xff0c;双击打开&#xff0c;选择Manual Scenario自…

《视觉 SLAM 十四讲》V2 第 9 讲 后端优化1 【扩展卡尔曼滤波器 EKF BA+非线性优化(Ceres、g2o)】

文章目录 第9讲 后端19.1.2 线性系统和 KF9.1.4 扩展卡尔曼滤波器 EKF 不足 9.2 BA 与 图优化9.2.1 投影模型和 BA 代价函数9.2.2 BA 的求解9.2.3 稀疏性 和 边缘化9.2.4 鲁棒核函数 9.3 实践&#xff1a; Ceres BA 【Code】本讲 CMakeLists.txt 9.4 实践&#xff1a;g2o 求解 …

100 # mongoose 的使用

mongoose elegant mongodb object modeling for node.js https://mongoosejs.com/ 安装 mongoose npm i mongoose基本示例 const mongoose require("mongoose");// 1、连接 mongodb let conn mongoose.createConnection("mongodb://kaimo313:kaimo313loc…

sql高级教程-索引

文章目录 架构简介1.连接层2.服务层3.引擎层4.存储层 索引优化背景目的劣势分类基本语法索引结构和适用场景 性能分析MySq| Query Optimizerexplain 索引优化单表优化两表优化三表优化 索引失效原因 架构简介 1.连接层 最上层是一些客户端和连接服务&#xff0c;包含本地sock通…

1 Go的前世今生

概述 Go语言正式发布于2009年11月&#xff0c;由Google主导开发。它是一种针对多处理器系统应用程序的编程语言&#xff0c;被设计成一种系统级语言&#xff0c;具有非常强大和有用的特性。Go语言的程序速度可以与C、C相媲美&#xff0c;同时更加安全&#xff0c;支持并行进程。…

[架构之路-241]:目标系统 - 纵向分层 - 企业信息化与企业信息系统(多台企业应用单机组成的企业信息网络)

目录 前言&#xff1a; 一、什么是信息系统&#xff1a;计算机软件硬件系统 1.1 什么是信息 1.2 什么是信息系统 1.3 什么是信息技术 1.4 什么是信息化与信息化转型 1.5 什么是数字化与数字化转型&#xff08;信息化的前提&#xff09; 1.6 数字化与信息化的比较 1.7 …

Zookeeper、Kafka集群与Filebeat+Kafka+ELK架构、部署实例

Zookeeper、Kafka集群与FilebeatKafkaELK架构、部署实例 一、Zookeeper1.1、Zookeeper 定义1.2、Zookeeper 工作机制1.3、Zookeeper 特点1.4、Zookeeper 数据结构1.5、Zookeeper 应用场景1.5、Zookeeper 选举机制1.5.1、 第一次启动选举机制1.5.2、 非第一次启动选举机制 二、Z…

二、UI入门

1. QWidget类 QWidget类是Qt所有图形用户界面&#xff08;组件&#xff09;的基类&#xff0c;因此QWidget类内部规定了所有最基础的UI相关功能。例如以下成员&#xff1a; ● width : const int 宽度&#xff08;单位&#xff1a;像素&#xff0c;后文同&#xff09; Qt中的…

数据结构-树的概念结构及存储

&#x1f5e1;CSDN主页&#xff1a;d1ff1cult.&#x1f5e1; &#x1f5e1;代码云仓库&#xff1a;d1ff1cult.&#x1f5e1; &#x1f5e1;文章栏目&#xff1a;数据结构专栏&#x1f5e1; 目录 一、树的基本概念及结构 1树的概念 2树的存储 二、二叉树的概念及结构 1二叉树的概…