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

嵌入式Day18--数据结构

1.数据结构的概念

定义

程序 == 数据结构 + 算法

数据结构:描述数据存储和操作的结构

算法:操作数据对象的方法

2.代码的质量和效率的衡量指标

时间复杂度

数据量的增长与程序运行时间的增长所呈现的比例函数关系,为时间渐进复杂函数,即时间复杂度

​​数据量越大,程序跑得越慢,时间复杂度用来衡量慢的增长程度

O(1):定程序运行时间与数据量无关,无论输入多大,执行时间基本恒定

O(logn):运行时间随数据量增长而增长,但增长非常缓慢,经过一定数据量大后趋于平缓

O(n):运行时间与数据量成正比

O(2^n):运行时间随数据量呈指数级增长

O(nlogn) O(n^2) O(n^3)

空间复杂度

数据的增长与程序占据空间的增长所呈现的比例函数关系,称为空间复杂度

数据量越大,程序占用的内存越多,空间复杂度用来衡量内存占用的增长趋势

3.分类

3.1逻辑结构

线性结构:表 (一对一)

非线性结构:树(一对多)、图(多对多)

3.2存储结构

顺序存储 链式存储 散列存储 索引存储

3.3常见的数据结构

顺序表 链式表

顺序栈 链式栈

顺序队列 链式队列

邻接表 邻接矩阵

二叉树

4.链表

4.1定义


4.2链表的相关操作

4.2.1定义节点类型

//存储的数据类型 typedef int Datatype_t; //链表结点类型 typedef struct node { Datatype_t data;//链表数据域 struct node* pnext;//链表指针域 }Node_t; //链表对象类型 typedef struct link { Node_t* phead;//链表头结点地址 int clen;//链表当前结点个数 }Link_t;

通过结构体定义链表节点的类型

其中数据 data 定义为 datatype_t,通过再次定义 int 为 datatype_t结点需要修改类型的地方

其中指向下一结点地址 pnext 定义为指针类型,通过指针链接各个结点

4.2.2创建空链表

空链表指链表中不储存实际数据的标点,可以视为头结点,头结点的下一个是真实的第一个数据

空链表可以让后续插入、删除、遍历等操作简便统一,不需要处理链表为空的情况

Link_t* create_link() { Link_t* plink = malloc(sizeof(Link_t)); if (NULL == plink) { printf("malloc error\n"); return NULL; } plink->phead = NULL; plink->clen = 0; return plink; }
  • malloc 申请空结点空间
  • data 不需要赋值(最好赋值),空白节点不存放数据,主要为了保证链表操作的便利性
  • pnext 赋值为 NULL,表示该节点为最后一个节点尾结点
  • 返回节点地址

4.2.3插入数据

头插法插入数据

头插法是在链表开头,即第一个有效数字前的位置插入新结点,使其成为新的头结点指向

插入第一个数据和插入中间数据本质一致,其都为将上一节点指向的地址存为新节点指向的地址,只是第一次插入数据的上一节点为空链表,指向为空,而自己本身成为尾结点(插入后自己指向为空)

int insert_link_head(Link_t* plink, Datatype_t data) { Node_t* pnode = malloc(sizeof(Node_t)); if (NULL == pnode) { printf("malloc error\n"); return -1; } pnode->data = data; pnode->pnext = NULL; pnode->pnext = plink->phead; plink->phead = pnode; plink->clen++; return 0; }
  • 申请新结点空间
  • 将需要插入的数据存放到空间中
  • 将上一结点指向的地址存放到空间指向的地址,即下一结点的地址
  • 将上一结点指向的地址更新为新结点的地址
尾插法插入数据

尾插法是​​在链表的末尾插入新结点​​。

尾插法保持原有节点顺序不变,新结点成为链表的最后一个元素,即尾结点

int insert_link_tail(Link_t* plink, Datatype_t data) { Node_t* pnode = malloc(sizeof(Node_t)); if (NULL == pnode) { printf("malloc error\n"); return -1; } pnode->data = data; pnode->pnext = NULL; if (is_empty_link(plink)) { plink->phead = pnode; } else { Node_t* ptmp = plink->phead; while (ptmp->pnext != NULL) { ptmp = ptmp->pnext; } ptmp->pnext = pnode; } plink->clen++; return 0; }

尾插法需要在头插法存入数据之前,将前一个结点指向尾结点再开始存入数据

通过遍历改变指针完成到达尾结点,遍历判断条件为 p->next 更便于找到尾结点

4.2.4遍历链表

int bianli_link(Link_t* plink) { Node_t* ptmp = plink->phead; while (NULL != ptmp) { printf("data is %d\n", ptmp->data); ptmp = ptmp->pnext; } printf("\n"); return 0; }

4.2.5删除数据

头删法删除数据
int delete_link_head(Link_t* plink) { if (is_empty_link(plink)) { return 0; } Node_t* pfree = plink->phead; plink->phead = pfree->pnext; free(pfree); plink->clen--; return 0; }
尾删法删除数据
int delete_link_tail(Link_t* plink) { if (is_empty_link(plink)) { return 0; } else if (1 == plink->clen) { delete_link_head(plink); } else { Node_t* pfree = plink->phead; while (pfree->pnext->pnext != NULL) { pfree = pfree->pnext; } free(pfree->pnext); pfree->pnext = NULL; plink->clen--; } return 0; }

在删除链表时还有其他情况需要考虑在内,即删除时链表是否为空,所以我们应该在删除时先判断一下链表是否为空

int is_empty_link(Link_t* plink) { if (NULL == plink->phead) { return 1; } return 0; }

4.2.6销毁链表

void destroy_link(Link_t* plink) { while(!is_empty_link(plink)) { delete_link_head(plink); } free(plink); }

4.2.7查找链表

查找链表中某一个结点
Node_t *find_link_node(Link_t* plink,Datatype_t data) { if(is_empty_link(plink)) { return NULL; } Node_t* ptmp=plink->phead; while(ptmp!=NULL) { if(ptmp->data == data) { return ptmp; } ptmp=ptmp->pnext; } return NULL; }
查找链表的中间结点
Node_t *find_mid_node(Link_t *plink) { if (is_empty_link(plink)) { return NULL; } Node_t *pfast = plink->phead; Node_t *pslow = pfast; while (pfast != NULL) { pfast = pfast->pnext; if (NULL == pfast) { break; } pfast = pfast->pnext; pslow = pslow->pnext; } return pslow; }

此处使用了快慢指针法,快指针的速度是慢指针的两倍,当快指针遍历完链表之后,慢指针的位置即为中间结点的位置。

查找链表倒数第K个结点
Node_t *find_k_node(Link_t* plink,int k) { if(is_empty_link(plink)) { return NULL; } Node_t* pfast=plink->phead; Node_t* pslow=pfast; for(int i=0;i<k;i++) { if(NULL == pfast) { return NULL; } pfast=pfast->pnext; } while(pfast!=NULL) { pfast=pfast->pnext; pslow=pslow->pnext; } return pslow; }

此处原理类似于查找链表的中间结点,快指针先走K步,然后快指针和慢指针以相同的速度遍历链表,当快指针遍历完链表后,慢指针所处的位置即为链表倒数第K个结点的位置。

4.2.8修改链表某一个结点的值

int change_link(Link_t *plink, Datatype_t new, Datatype_t old) { Node_t *ptmp = NULL; ptmp = find_link_node(plink, old); if (ptmp != NULL) { ptmp->data = new; return 0; } return -1; }

4.2.9链表的倒置

void reverse_link(Link_t* plink) { if(is_empty_link(plink)) { return ; } Node_t* pinsert=NULL; Node_t* ptmp=plink->phead; plink->phead=NULL; while(ptmp!= NULL) { pinsert=ptmp; ptmp=ptmp->pnext; pinsert->pnext=plink->phead; plink->phead=pinsert; } return ; }

4.2.10链表的排序

此处选择的是插入排序的算法

void sort_link_insert(Link_t* plink) { if(is_empty_link(plink) || 1 == plink->clen) { return ; } Node_t* pinsert=NULL; Node_t* ptmp=plink->phead->pnext; plink->phead->pnext=NULL; while(ptmp!=NULL) { pinsert=ptmp; ptmp=ptmp->pnext; if(pinsert->data<=plink->phead->data) { pinsert->pnext=plink->phead; plink->phead=pinsert; } else { Node_t* p=plink->phead; while(p->pnext!=NULL && p->pnext->data<pinsert->data) { p=p->pnext; } pinsert->pnext=p->pnext; p->pnext=pinsert; } } }

4.2.11判断链表是否有环

int is_loop_link(Link_t* plink) { Node_t* pfast=plink->phead; Node_t* pslow=pfast; while(pfast!=NULL) { pfast=pfast->pnext; if(NULL == pfast) { return 0; } pfast=pfast->pnext; pslow=pslow->pnext; if(pslow == pfast) { return 1; } } return 0; }
http://www.rkmt.cn/news/1385007.html

相关文章:

  • AI 英语学习APP的开发
  • P1059 [NOIP 2006 普及组] 明明的随机数
  • 别再手动查IP了!用XShell/Xftp连接Ubuntu的保姆级配置流程(含SSH开启失败解决方案)
  • XML 服务器
  • 3步实现NVIDIA显卡硬件级色彩校准:novideo_srgb完整指南
  • 自动化程序验证中的智能体证明能力
  • AI学习 - 大模型基础入门
  • Mysql:事务管理(中)
  • YOLOv11卫生间卫浴设备目标检测数据集-2978张-washroom-1
  • 终极跨平台控制器适配方案:让Switch手柄在PC上焕发新生
  • 【Elasticsearch从入门到精通】第33篇:Elasticsearch过滤器聚合与嵌套聚合——filter、filters与adjacency_matrix
  • 山东大学-杏林集:智汇中医-项目实训(七)
  • 洛雪音乐桌面版:打造你的跨平台音乐聚合播放器终极体验
  • 5分钟掌握NCM解密:解锁网易云音乐格式转换的完整指南
  • 055全排列
  • 零基础转行网络安全!通俗拆解行业岗位、能力要求与发展路径
  • 大佬推荐的网络安全学习路线(从基础到高级,超级详细)
  • AI圈神秘领袖Ilya一幅画引爆全网,OpenAI三件大事暗示AGI时代将至?
  • 集成学习在房价预测中的应用:从原理到实战调优
  • 【Unity编辑器拓展】实现ScriptableObject的结构体结构中,枚举变量显示中文描述
  • 不止于采样:深度挖掘英飞凌Aurix EVADC的硬件触发与高级仲裁机制
  • APIfox自动化测试实战:如何用后置脚本实现接口间数据传递(含公共断言脚本写法)
  • 为Claude Code配置Taotoken解决访问不稳定与Token不足难题
  • 毕业设计:基于java的在线问卷调查系统的设计与实现(源码)
  • 2026年第20周最热门的开源项目(Github)
  • Android 高频面试题汇总,26 道经典考题轻松应对面试
  • Airtest Poco实战:5分钟搞定微信小程序自动化测试环境搭建与元素抓取
  • 关联规则挖掘在Calabi-Yau流形Hodge数分析中的应用与复现
  • 优化器偷偷做了什么:一次子查询消除让我从32秒等到24毫秒
  • 别再乱点屏幕了!用Monkey黑白名单精准测试你的Android App(附完整配置文件)