嵌入式学习——数据结构(单向无头链表)——day46

1. 数据结构

1.1 定义

        数据结构是指计算机中数据的组织、管理和存储方式。它不仅包括数据元素的存储方式,还包括数据元素之间的关系,以及对数据进行操作的方法和算法。数据结构的选择和设计直接影响算法的效率和程序的性能,是计算机科学与编程中非常重要的基础

1.2 数据结构的分类

(1)逻辑角度

        1. 线性结构(一对一)数组、链表、队列、栈

        2. 树型结构(一对多)二叉树

        3. 图形结构(多对多)网状结构

(2)存储角度

        1. 顺序存储:采用一段连续的内存空间保存元素(数组)

                        优点:空间连续,访问方便

                        缺点:插入删除需要移动大量元素、需要预分配内存空间,容易造成存储空间碎片

        2. 链式存储:采用一组非连续的内存空间保存元素(链表)

                        优点:插入和删除数据方便、不需要预分配内存

                        缺点:访问元素效率低

        3. 散列存储(哈希存储)将数据元素的存储位置与关键码之间建立确定对应关系从而实现查找的存储方式

        4. 索引存储:通过关键字构建索引表、通过索引表来找到数据的存储位置

补充:

        1. 重点学习内容

        顺序表、链式表、顺序栈、链式栈、顺序队列、链式队列、二叉树、哈希表

        2. 程序  =  数据结构 + 算法 

2. 分析算法效率的两个指标

2.1 时间复杂度

        是指算法在执行过程中所需时间的量度。它衡量的是算法的执行时间随输入规模的变化情况,通常用大O记号表示,如O(n)、O(log n)等

2.2 空间复杂度

        是指算法在执行过程中所需存储空间的量度。它衡量的是算法的内存使用情况,通常也用大O记号表示。

3.无头单向链表代码

3.1 makefile

OBJ:=seqlist
OBJS+=SeqList.c
CC:=gcc $(OBJ):$(OBJS)$(CC) $^ -o $@
.PHONY:
clean:rm $(OBJ)
test:valgrind --tool=memcheck --leak-check=full ./$(OBJ)

3.2 头文件

#ifndef _LINKLIST_H_
#define _LINKLIST_H_#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef int DataType;typedef struct node
{DataType Data;struct node *pNext;
}LinkNode;typedef struct list
{LinkNode *pHead;int cLen;
}LinkList;extern LinkList *create_LinkList(void);
extern int is_empty_link(LinkList *pTmpList);
extern int push_head_link(LinkList *pTmpList, DataType Data);//头插、空链表也能使用
extern int push_tail_link(LinkList *pTmpList, DataType Data);//尾插、空链表也能使用
extern void link_for_each(LinkList *pTmpList);
extern int pop_head_link(LinkList *pTmpList);
extern int pop_tail_link(LinkList *pTmpList);
extern LinkNode *find_data(LinkList *pTmpList, DataType Data);
extern int modify_data(LinkList *pTmpList, DataType old_data, DataType new_data);
extern void destory_link(LinkList *pTmpList);
extern LinkNode *find_mid_node(LinkList *pTmpList);//找中间节点
extern LinkNode *find_last_k_node(LinkList *pList, int k);//寻找倒数第k个节点
extern int pop_data_link(LinkList *pTmpList, DataType Data);//删除数据为key的节点
extern void invert_link(LinkList *pTmpList);
extern void insert_sort_link(LinkList *pTmpList);#endif

3.3 主函数

#include "LinkList.h"LinkList *create_LinkList(void)//创建空链表
{LinkList *pList = NULL;pList = malloc(sizeof(LinkList));if (NULL == pList){perror("fail to malloc");return NULL;}pList->pHead = NULL;pList->cLen = 0;return pList;
}int is_empty_link(LinkList *pTmpList)//判断链表是否为空链表
{if (NULL == pTmpList->pHead){return 1;}return 0;
}int push_head_link(LinkList *pTmpList, DataType Data)//头插、空链表也能使用
{LinkNode *pTmpNode = NULL;pTmpNode = malloc(sizeof(LinkNode));if (NULL == pTmpNode){perror("fail to malloc");return -1;}pTmpNode->pNext = NULL;//插入节点初始化pTmpNode->Data = Data;pTmpNode->pNext = pTmpList->pHead;pTmpList->pHead = pTmpNode;pTmpList->cLen++;return 0;
}int push_tail_link(LinkList *pTmpList, DataType Data)//尾插、空链表也能使用
{LinkNode *pTmpNode = NULL;LinkNode *pLastNode = NULL;pTmpNode = malloc(sizeof(LinkNode));if (NULL == pTmpNode){perror("fail to malloc");return -1;}pTmpNode->pNext = NULL;pTmpNode->Data = Data;if (is_empty_link(pTmpList)){pTmpList->pHead = pTmpNode;}else {pLastNode = pTmpList->pHead;while (pLastNode->pNext != NULL){pLastNode = pLastNode->pNext;}pLastNode->pNext = pTmpNode;}pTmpList->cLen++;return 0;
}void link_for_each(LinkList *pTmpList)//遍历输出链表
{LinkNode *pTmpNode = NULL;pTmpNode = pTmpList->pHead;while (pTmpNode != NULL){printf("%d ", pTmpNode->Data);pTmpNode = pTmpNode->pNext;}putchar('\n');
}int pop_head_link(LinkList *pTmpList)//头删
{if (is_empty_link(pTmpList)){return -1;}LinkNode *pTmpNode = NULL;pTmpNode = pTmpList->pHead;pTmpList->pHead = pTmpNode->pNext;free(pTmpNode);pTmpList->cLen--;return 0;
}int pop_tail_link(LinkList *pTmpList)//尾删
{if (is_empty_link(pTmpList)){return -1;}if (1 == pTmpList->cLen){pop_head_link(pTmpList);}else{LinkNode *pTmpNode = NULL;pTmpNode = pTmpList->pHead;while (pTmpNode->pNext->pNext != NULL){pTmpNode = pTmpNode->pNext;}free(pTmpNode->pNext);pTmpNode->pNext = NULL;pTmpList->cLen--;}return 0;
}LinkNode *find_data(LinkList *pTmpList, DataType Data)//在链表中寻找数据
{LinkNode *pTmpNode = NULL;pTmpNode = pTmpList->pHead;while (pTmpNode){if (Data == pTmpNode->Data){return pTmpNode;}pTmpNode = pTmpNode->pNext;}return NULL;
}int modify_data(LinkList *pTmpList, DataType old_data, DataType new_data)//修改数据
{LinkNode *pTmpNode = NULL;pTmpNode = find_data(pTmpList, old_data);if (pTmpNode != NULL){pTmpNode->Data = new_data;return 0;}else {return -1;}
}void destory_link(LinkList *pTmpList)//销毁链表
{while (!is_empty_link(pTmpList)){pop_head_link(pTmpList);}free(pTmpList);
}LinkNode *find_mid_node(LinkList *pTmpList)//找中间节点
{LinkNode *pSlowNode = NULL;LinkNode *pFastNode = NULL;pFastNode = pTmpList->pHead;pSlowNode = pFastNode;while (pFastNode != NULL){pFastNode = pFastNode->pNext;if (NULL == pFastNode){break;}pFastNode = pFastNode->pNext;//pFastNode 速度是 pSlowNode的两倍pSlowNode = pSlowNode->pNext;}return pSlowNode;
}LinkNode *find_last_k_node(LinkList *pTmpList, int k)//寻找倒数第k个节点
{LinkNode *pFastNode = NULL;LinkNode *pSlowNode = NULL;int i = 0;pFastNode = pTmpList->pHead;pSlowNode = pFastNode;for (i = 0; i < k; i++)//快慢指针相差k个位置{if (NULL == pFastNode){return NULL;}pFastNode = pFastNode->pNext;}while (pFastNode != NULL){pFastNode = pFastNode->pNext;pSlowNode = pSlowNode->pNext;}return pSlowNode;
}int pop_data_link(LinkList *pTmpList, DataType Data)//删除数据为key的节点
{if (is_empty_link(pTmpList)){return 1;}LinkNode *pTmpNode = NULL;LinkNode *pPreNode = NULL;pTmpNode = pTmpList->pHead;while (pTmpNode != NULL){if (Data == pTmpNode->Data)//找到数据{if (pTmpNode == pTmpList->pHead)//判断是否只有头结点{pTmpList->pHead = pTmpNode->pNext;free(pTmpNode);pTmpNode = pTmpList->pHead;}else{pPreNode->pNext = pTmpNode->pNext;free(pTmpNode);pTmpNode = pPreNode->pNext;}pTmpList->cLen--;}else{pPreNode = pTmpNode;pTmpNode = pTmpNode->pNext;}}
}void invert_link(LinkList *pTmpList)//链表的倒置
{LinkNode *pTmpNode = NULL;LinkNode *pInsertNode = NULL;pTmpNode = pTmpList->pHead;pTmpList->pHead = NULL;while (pTmpNode != NULL){pInsertNode = pTmpNode;pTmpNode = pTmpNode->pNext;pInsertNode->pNext = pTmpList->pHead;pTmpList->pHead = pInsertNode;}
}void  insert_sort_link(LinkList *pTmpList)
{if (is_empty_link(pTmpList) || NULL == pTmpList->pHead->pNext)//空链表或者只有一个节点,不用排序{return ;}LinkNode *pTmpNode = NULL;//记录剩余节点的起始位置LinkNode *pInsertNode = NULL;//插入节点的位置LinkNode *p = NULL;//插入排序中遍历已经插入的节点的指针pTmpNode = pTmpList->pHead->pNext;//第一个节点不排序,从第二个节点开始排序pTmpList->pHead->pNext = NULL;//从原链表的第一个节点之后断开while (pTmpNode != NULL)//判断剩余未排序节点是否存在,最后一个节点参与操作{pInsertNode = pTmpNode;pTmpNode = pTmpNode->pNext;if (pInsertNode->Data <= pTmpList->pHead->Data)//判断要插入节点数据的大小是否小于第一个节点的数据{pInsertNode->pNext = pTmpList->pHead;//头插pTmpList->pHead = pInsertNode;}else //往后插{p = pTmpList->pHead;while (p->pNext != NULL && p->pNext->Data < pInsertNode->Data){p = p->pNext;}pInsertNode->pNext = p->pNext;p->pNext = pInsertNode;}}
}int main(void)
{LinkList *pList = NULL;LinkNode *pTmpNode = NULL;pList = create_LinkList();//创建if (NULL == pList){return -1;}
#if 0push_head_link(pList, 3);//头插push_head_link(pList, 2);push_head_link(pList, 1);link_for_each(pList);
#endifpush_tail_link(pList, 1);//尾插push_tail_link(pList, 2);push_tail_link(pList, 3);push_tail_link(pList, 4);push_tail_link(pList, 5);push_tail_link(pList, 6);push_tail_link(pList, 7);link_for_each(pList);
#if 0pop_head_link(pList);//头删link_for_each(pList);pop_tail_link(pList);//尾删link_for_each(pList);
#endifpTmpNode = find_data(pList, 4);//找数据if (NULL != pTmpNode){printf("find node data = %d\n", pTmpNode->Data);}else{printf("not find this node\n");}modify_data(pList, 2, 20);//修改数据modify_data(pList, 3, 30);modify_data(pList, 4, 40);modify_data(pList, 5, 50);link_for_each(pList);pTmpNode = find_mid_node(pList);//找链表中间节点if (pTmpNode != NULL){printf("Mid node data = %d\n", pTmpNode->Data);}link_for_each(pList);pTmpNode = find_last_k_node(pList, 5);//寻找链表倒数第k个节点if (pTmpNode != NULL){printf("last node data = %d\n", pTmpNode->Data);}link_for_each(pList);pop_data_link(pList, 30);//删除链表数据link_for_each(pList);invert_link(pList);//链表倒置link_for_each(pList);insert_sort_link(pList);link_for_each(pList);destory_link(pList);//销毁链表return 0;
}

4. 快慢双指针解决链表问题

4.1 寻找中间节点——(后面的指针前进速度是前面指针的一半)

LinkNode *find_mid_node(LinkList *pTmpList)//找中间节点
{LinkNode *pSlowNode = NULL;LinkNode *pFastNode = NULL;pFastNode = pTmpList->pHead;pSlowNode = pFastNode;while (pFastNode != NULL)//要操作pFastNod{pFastNode = pFastNode->pNext;if (NULL == pFastNode){break;}pFastNode = pFastNode->pNext;//pFastNode 速度是 pSlowNode的两倍pSlowNode = pSlowNode->pNext;}return pSlowNode;
}

4.2 寻找倒数第k个节点——(两指针相差k)

LinkNode *find_last_k_node(LinkList *pTmpList, int k)//寻找倒数第k个节点
{LinkNode *pFastNode = NULL;LinkNode *pSlowNode = NULL;int i = 0;pFastNode = pTmpList->pHead;pSlowNode = pFastNode;for (i = 0; i < k; i++)//快慢指针相差k个位置{if (NULL == pFastNode)//节点数不足k程序直接结束{return NULL;}pFastNode = pFastNode->pNext;}while (pFastNode != NULL){pFastNode = pFastNode->pNext;pSlowNode = pSlowNode->pNext;}return pSlowNode;
}

4.3 删除数据为key的节点

int pop_data_link(LinkList *pTmpList, DataType Data)//删除数据为key的节点
{if (is_empty_link(pTmpList)){return -1;}LinkNode *pTmpNode = NULL;LinkNode *pPreNode = NULL;pTmpNode = pTmpList->pHead;while (pTmpNode != NULL){if (Data == pTmpNode->Data)//找到数据{if (pTmpNode == pTmpList->pHead)//判断是否只有头结点{pTmpList->pHead = pTmpNode->pNext;free(pTmpNode);pTmpNode = pTmpList->pHead;}else{pPreNode->pNext = pTmpNode->pNext;free(pTmpNode);pTmpNode = pPreNode->pNext;}pTmpList->cLen--;}else{pPreNode = pTmpNode;pTmpNode = pTmpNode->pNext;}}
}

5. 单向链表算法

5.1 链表的倒置

void invert_link(LinkList *pTmpList)//链表的倒置
{LinkNode *pTmpNode = NULL;LinkNode *pInsertNode = NULL;pTmpNode = pTmpList->pHead;pTmpList->pHead = NULL;//断开链表while (pTmpNode != NULL){pInsertNode = pTmpNode;pTmpNode = pTmpNode->pNext;pInsertNode->pNext = pTmpList->pHead;pTmpList->pHead = pInsertNode;}
}

5.2 链表的插入排序(从小到大)

void  insert_sort_link(LinkList *pTmpList)//插入排序法
{if (is_empty_link(pTmpList) || NULL == pTmpList->pHead->pNext)//空链表或者只有一个节点,不用排序{return ;}LinkNode *pTmpNode = NULL;//记录剩余节点的起始位置LinkNode *pInsertNode = NULL;//插入节点的位置LinkNode *p = NULL;//插入排序中遍历已经插入的节点的指针pTmpNode = pTmpList->pHead->pNext;//第一个节点不排序,从第二个节点开始排序pTmpList->pHead->pNext = NULL;//从原链表的第一个节点之后断开while (pTmpNode != NULL)//判断剩余未排序节点是否存在,最后一个节点参与操作{pInsertNode = pTmpNode;pTmpNode = pTmpNode->pNext;if (pInsertNode->Data <= pTmpList->pHead->Data)//判断要插入节点数据的大小是否小于第一个节点的数据{pInsertNode->pNext = pTmpList->pHead;//头插pTmpList->pHead = pInsertNode;}else //往后插{p = pTmpList->pHead;while (p->pNext != NULL && p->pNext->Data < pInsertNode->Data){p = p->pNext;}pInsertNode->pNext = p->pNext;p->pNext = pInsertNode;}}
}

6. 测试链表是否被销毁

        valgrind ./a.out——查看开辟的空间是否全部被释放

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

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

相关文章

说一说三大运营商的流量类型,看完就知道该怎么选运营商了!

说一说三大运营商的流量类型&#xff0c;看完就知道该怎么选运营商了&#xff1f;目前三大运营商的流量类型大致分为通用流量和定向流量&#xff0c;比如&#xff1a; 中国电信&#xff1a;通用流量定向流量 电信推出的套餐通常由通用流量定向流量所组成&#xff0c;通用流量…

【Python时序预测系列】基于LSTM实现单变量时序序列多步预测(案例+源码)

这是我的第307篇原创文章。 一、引言 单站点单变量输入单变量输出多步预测问题----基于LSTM实现。 单输入就是输入1个特征变量 单输出就是预测出1个标签的结果 多步就是利用过去N天预测未来M天的结果 二、实现过程 2.1 读取数据集 # 读取数据集 data pd.read_csv(data.c…

HTML5文旅文化旅游网站模板源码

文章目录 1.设计来源文旅宣传1.1 登录界面演示1.2 注册界面演示1.3 首页界面演示1.4 文旅之行界面演示1.5 文旅之行文章内容界面演示1.6 关于我们界面演示1.7 文旅博客界面演示1.8 文旅博客文章内容界面演示1.9 联系我们界面演示 2.效果和源码2.1 动态效果2.2 源代码2.3 源码目…

笔记本电脑屏幕模糊?6招恢复屏幕清晰!

在数字化时代的浪潮中&#xff0c;笔记本电脑已成为我们生活、学习和工作中不可或缺的一部分。然而&#xff0c;当那曾经清晰明亮的屏幕逐渐变得模糊不清时&#xff0c;无疑给我们的使用体验蒙上了一层阴影。屏幕模糊不仅影响视觉舒适度&#xff0c;更可能对我们的工作效率和眼…

【AI大模型】驱动的未来:穿戴设备如何革新血液、皮肤检测与营养健康管理

文章目录 1. 引言2. 现状与挑战3. AI大模型与穿戴设备概述4. 数据采集与预处理4.1 数据集成与增强4.2 数据清洗与异常检测 5. 模型架构与训练5.1 高级模型架构5.2 模型训练与调优 6. 个性化营养建议系统6.1 营养建议生成优化6.2 用户反馈与系统优化 7. 关键血液成分与健康状况评…

WIN Semis揭幕耐湿砷化镓pHEMT技术

​犹如为无线通信领域注入了一股清新的活力。这项技术不仅支持E频带&#xff0c;更在晶圆级上筑起了一道坚固的防潮屏障&#xff0c;满足了对严苛环境条件的bHAST挑战。今日&#xff0c;WIN半导体公司正式公布了0.1m pHEMT技术PP10-29的测试版&#xff0c;预示着通信领域的新篇…

ansible 任务块以及循环

任务块 可以通过block关键字&#xff0c;将多个任务组合到一起可以将整个block任务组&#xff0c;一起控制是否要执行 # 如果webservers组中的主机系统发行版是Rocky&#xff0c;则安装并启动nginx [rootpubserver ansible]# vim block1.yml --- - name: block tasks hosts…

ROS2从入门到精通4-4:局部控制插件开发案例(以PID算法为例)

目录 0 专栏介绍1 控制插件编写模板1.1 构造控制插件类1.2 注册并导出插件1.3 编译与使用插件 2 基于PID的路径跟踪原理3 控制插件开发案例(PID算法)常见问题 0 专栏介绍 本专栏旨在通过对ROS2的系统学习&#xff0c;掌握ROS2底层基本分布式原理&#xff0c;并具有机器人建模和…

Go 如何使用指针灵活操作内存

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

爬虫笔记14——爬取网页数据写入MongoDB数据库,以爱奇艺为例

下载MongoDB数据库 首先&#xff0c;需要下载MongoDB数据库&#xff0c;下载的话比较简单&#xff0c;直接去官网找到想要的版本下载即可&#xff0c;具体安装过程可以看这里。 pycharm下载pymongo库 pip install pymongo然后在在python程序中我们可以这样连接MongoDB数据库…

IPD推行成功的核心要素(十三)IPD产品开发流程让企业正确地做事情

一个公司能否成功&#xff0c;取决于它适应市场需求和竞争环境变化的速度。公司需要不断创新&#xff0c;以符合客户期望并保持相关性。这意味着需要更快速地推出新产品和改进产品。简化的产品开发流程能够支持快速开发周期&#xff0c;帮助公司领先于市场&#xff0c;用优秀的…

植物大战僵尸杂交版2.1版本终于来啦!游戏完全免费

在这个喧嚣的城市里&#xff0c;我找到了一片神奇的绿色世界——植物大战僵尸杂交版。它不仅是一款游戏&#xff0c;更像是一扇打开自然奥秘的窗户&#xff0c;让我重新认识了植物和自然的力量。 植物大战僵尸杂交版最新绿色版下载链接&#xff1a; https://pan.quark.cn/s/d6…

MySQL的综合运用

MySQL版的葵花宝典&#xff0c;欲练此功&#xff0c;挥刀自。。。呃&#xff0c;&#xff0c;&#xff0c;说错了&#xff0c;是先创建两个表&#xff0c;分别是location表和store_info表 示例表为location表和store_info表&#xff0c;如下图所示&#xff1a; 操作一&#xf…

【C++高阶】掌握AVL树:构建与维护平衡二叉搜索树的艺术

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ ⏩收录专栏⏪&#xff1a;C “ 登神长阶 ” &#x1f921;往期回顾&#x1f921;&#xff1a;STL-> map与set &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀AVL树 &#x1f4d2;1. AVL树…

JavaSE (Java基础):运算符

3 运算符 3.1 二元运算符 为什么下面这段代码中最后的语句中b元素要加&#xff08;double&#xff09;呢&#xff1f; 因为要计算10/40的话&#xff0c;他们都是int类型的在计算机中会取整&#xff0c;而计算机取整一般都是直接舍去小数点后面的数字&#xff0c;那么就会返回0&…

VScode基本使用

VScode下载安装&#xff1a; Visual Studio Code - Code Editing. Redefined MinGW的下载安装&#xff1a; MinGW-w64 - for 32 and 64 bit Windows - Browse Files at SourceForge.net x86是64位处理器架构&#xff0c;i686是32为处理器架构。 POSIX和Win32是两种不同的操…

vscode pip : 无法将“pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称

在vscode中控制台运行python文件出现&#xff1a;无法将"pip”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。 使用vscode开发python&#xff0c;需要安装python开发扩展&#xff1a; 本文已经安装&#xff0c;我们需要找的是python安装所在目录&#xff0c;本文…

【云原生】Kubernetes----证书过期处理办法

目录 引言 一、证书过期的问题与影响 二、解决方案 &#xff08;一&#xff09;查看证书剩余时间 &#xff08;二&#xff09;备份重要数据 &#xff08;三&#xff09;更新证书 &#xff08;四&#xff09;重启相关组件的pod 引言 随着云计算技术的飞速发展&#xff0…

消息认证码解析

1. 什么是消息认证码 消息认证码(Message Authentication Code)是一种确认完整性并进行认证的技术&#xff0c;取三个单词的首字母&#xff0c;简称为MAC。 消息认证码的输入包括任意长度的消息和一个发送者与接收者之间共享的密钥&#xff0c;它可以输出固定长度的数据&#x…

[分布式网络通讯框架]----ZooKeeper下载以及Linux环境下安装与单机模式部署(附带每一步截图)

首先进入apache官网 点击中间的see all Projects->Project List菜单项进入页面 找到zookeeper&#xff0c;进入 在Zookeeper主页的顶部点击菜单Project->Releases&#xff0c;进入Zookeeper发布版本信息页面&#xff0c;如下图&#xff1a; 找到需要下载的版本 …