嵌入式学习——数据结构(单向无头链表)——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,一经查实,立即删除!

相关文章

uniapp 低功耗蓝牙BLE分包

ble.js // 分包写入蓝牙async sendWriteBLECharacteristicValue(deviceId,serviceId,writeCharacteristicId,readCharacteristicId,buffer,success, // 成功回调failure, // 失败回调) {const offset 500; // 偏移量let pos 0; // 位置let bytes buffer.byteLength; // 总字…

.env 文件详解(vite)

.env.development 开发环境.env.production 正式环境.env.test 测试环境 .env文件内容&#xff1a; 开发环境 # 当前环境&#xff0c;VITE_ 开头 VITE_NODE_ENV development # 请求基地址 VITE_BASE_URL /api # 本地代理目标地址&#xff0c;在proxy里面target里面用 VITE…

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

说一说三大运营商的流量类型&#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 源码目…

Spring Boot框架原理及应用详解(三)

本系列文章简介: 在当今的软件开发世界中,快速迭代、高效开发以及易于维护成为了开发者们不断追求的目标。Spring Boot作为Spring框架的一个子项目,自其诞生以来就凭借其“约定大于配置”的理念和自动配置的特性,迅速在Java开发社区中获得了广泛的关注和认可。它简化了Spri…

QT 中ListView和ListWidget有什么区别

ListView和ListWidget在Qt框架中都是用于显示列表数据的控件&#xff0c;但它们在使用方法和特性上存在一些明显的差异。以下是关于它们用法不一样的地方的详细分析&#xff1a; 数据管理方式&#xff1a; ListView&#xff1a;使用QAbstractItemModel数据模型来管理和显示列表…

electron录制应用-自由画板功能

功能 录屏过程中的涂画功能允许用户在录制屏幕操作的同时&#xff0c;实时添加注释和高亮显示&#xff0c;以增强信息的传达和观众的理解。 效果 electron录制-添加画布 代码实现 1、利用HTML5的Canvas元素实现一个自由涂画的功能&#xff0c;允许用户在网页上进行手绘创作。…

笔记本电脑屏幕模糊?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;预示着通信领域的新篇…

React学习(一)

React的详细解析: 1. React的起源与背景 React起源于Facebook的内部项目&#xff0c;旨在解决市场上JavaScript MVC框架的不足之处。React的早期原型被称为“FaxJS”&#xff0c;由Facebook工程师Jordan Walke开发&#xff0c;深受XHP&#xff08;一个简单的PHP HTML组件框架…

ansible 任务块以及循环

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

墨刀原型工具-小白入门篇

墨刀原型工具-小白入门篇 简介 随着互联网的发展和用户体验的重要性越来越受到重视&#xff0c;原型设计逐渐成为了产品设计中的重要环节。墨刀作为一款原型设计工具&#xff0c;以其简洁、易用的特点&#xff0c;受到了很多设计师的喜爱。本文将介绍墨刀原型工具的基本使用方…

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的主页」…

Leetcode 3196. Maximize Total Cost of Alternating Subarrays

Leetcode 3196. Maximize Total Cost of Alternating Subarrays 1. 解题思路2. 代码实现 题目链接&#xff1a;3196. Maximize Total Cost of Alternating Subarrays 1. 解题思路 这一题就是一个动态规划&#xff0c;只需要考虑每一个元素作为开始和处于序列当中的二元态即可…

深度学习引言

深度学习引言 什么是神经网络&#xff1f; 我们常常用深度学习这个术语来指训练神经网络的过程。有时它指的是特别大规模的神经网络训练。 神经网络的监督学习 关于神经网络也有很多的种类&#xff0c;考虑到它们的使用效果&#xff0c;有些使用起来恰到好处&#xff0c;但事实…

90天瘦30斤瘦身计划

90天瘦30斤瘦身计划 重要提示&#xff1a; 在开始任何减肥计划之前&#xff0c;强烈建议咨询医生或营养师以确保该计划适合您的健康状况。减肥过快可能对身体健康产生负面影响&#xff0c;因此请确保您的方法既安全又可持续。 目标&#xff1a; 在90天内健康地减轻30斤体重。…

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

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