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

嵌入式解谜日志之数据结构—基本概念

数据结构

(1)定义:相互之间存在一种或多种特定关系的数据元素的集合

(2)逻辑结构分类:

  1. 集合:所有数据在同一集合中,关系平等
  2. 线性:数据和数据之间一对一的关系
  3. 树:一对多(目录)
  4. 图:多对多(地图,网)
(3)物理结构(在内存当中的存储关系)
  1. 顺序存储:数据存放在连续的存储单位中。逻辑关系和物理关系一致
  2. 链式:数据存放的存储单位是随机或任意的,可以连续也可以不连续
struct Per数据元素
{char name;//数据项int age;char phone;
}struct Per list[100]; //数据对象

数据对象为一个集合——》包含了多个数据元素——》数据元素有多个数据项组成——》数据项由变量组成

(4)数据的类型:ADT(abstruct datatype):是指一组性质相同的值的集合及定义在此集合上的一些操作的总称。

抽象数据类型=数学模型+操作

(5)程序=数据+算法

1.算法

  1. 是解决特定问题求解步骤的描述,计算机中表现为指令的有限序列,每条指令表示一个或多个操作。(函数及函数的调用)
①算法的特征
  1. 输入输出特性:输入是可选的,输出是必须的(可以没有传参)
  2. 有穷性:执行的步骤会自动结束,不能是死循环,并且每一步是在可以接受的时间内完成(不能死循环,并且每一步都可以在接受的时间内完成)
  3. 确定性:同一个输入,会得到唯一的输出
  4. 可行性:每一个步骤都是可以实现的
②算法设计要求
  1. 正确性

    • 语法正确
    • 合法的输入能得到合理的结果
    • 对非法的输入,给出满足要求的规格说明
    • 对精心选择,甚至刁难的测试都能正常运行,结果正确
  2. 可读性:便于交流,阅读,理解(画流程图,给程序备注)

  3. 健壮性:输入非法数据,能进行相应的处理,而不是产生异常

  4. 高效性:存储低,效率高(代码简化)

③算法时间复杂度分析(衡量算法的好坏)

算法时间复杂度是执行这个算法所花时间的度量。

④时间复杂度推导规则:(事前分析法)
  1. 用常数1取代运行时间中的所有加法常数
  2. 在修改后的运行函数中,只保留最高阶项
  3. 如果最高阶存在且不是1,则取除这个项相乘的常数
⑤常见时间复杂度排序

O(1) < O(logn) < O(N) < O(nlogn) < O(n²) (for嵌套)< O(n³) < O(2ⁿ) < O(n!) < O(nⁿ)

时间复杂度越小越好算法越好

// 示例1:基本循环
int i, sum; // 8 
for(10000)    // n次循环
{sum = i+sum;  // 2n +3
}
a = c;
b = c;
a = d;
// 时间复杂度:O(n)// 示例2:数学公式计算
int n;  // 4
n = (n+1)*n/2;  // 4
// 时间复杂度:O(1)// 示例3:嵌套循环
for(i=0; i<n; i++)  // n次
{for(j=0; j<n; j++)  // n次{// 执行操作}
}
// 时间复杂度:O(n²)

线性表:零个或多个数据元素的有限序列

顺序表:存储空间是连续的

特征:支持随机访问--head+5 head[0]   O(1)

劣势:①插入,删除需要整体移动  O(N)

           ②不支持动态存储功能。(空间不能随着使用量自动变化,需要手动修改)

(1)线性表特征

  • 元素之间是有顺序的
  • 如果存在多个元素,第一个元素无前驱,最后一个没有后继
  • 其他的元素只有一个前驱和一个后继
  • 当线性表元素的个数n(n>=0)定义为线性表的长度
  • 当n=0时,为空表
  • 在非空的表中每个元素都有一个确定的位置

(2)线性表的常规操作ADT

typedef struct person
{char name[32];char sex;int age;int score;
}DATATYPE;    //给结构体struct person取个别名:DATATYPEtypedef struct list
{DATATYPE *head;     //数组指针int Tlen;        //数组的容量int Clen;        //数组有效元素个数
}Seqlist;            //表头结构
/** 创建顺序表* 参数:len - 顺序表的初始容量* 返回值:成功返回创建的顺序表指针,失败返回NULL*/
SeqList *CreateSeqList(int len);/** 销毁顺序表* 参数:list - 要销毁的顺序表指针* 返回值:0表示成功,非0表示失败*/
int DestroySeqList(SeqList *list);/** 显示顺序表中的所有元素* 参数:list - 要显示的顺序表指针* 返回值:0表示成功,非0表示失败(如顺序表为空或不存在)*/
int ShowSeqList(SeqList *list);/** 在顺序表尾部插入元素* 参数:list - 目标顺序表指针;data - 要插入的数据元素* 返回值:0表示成功,非0表示失败(如顺序表已满)*/
int InsertTailSeqList(SeqList *list, DATATYPE data);/** 判断顺序表是否已满* 参数:list - 要判断的顺序表指针* 返回值:1表示已满,0表示未满,-1表示参数无效*/
int IsFullSeqList(SeqList *list);/** 判断顺序表是否为空* 参数:list - 要判断的顺序表指针* 返回值:1表示为空,0表示非空,-1表示参数无效*/
int IsEmptySeqList(SeqList *list);/** 在顺序表指定位置插入元素* 参数:list - 目标顺序表指针;data - 要插入的数据元素;pos - 插入位置(从0开始)* 返回值:0表示成功,非0表示失败(如位置无效或表已满)*/
int InsertPosSeqList(SeqList *list, DATATYPE data, int pos);/** 在顺序表中查找指定名称的元素* 参数:list - 要查找的顺序表指针;name - 要查找的名称字符串* 返回值:成功返回元素位置索引(从0开始),失败返回-1*/
int FindSeqList(SeqList *list, char *name);/** 修改顺序表中指定名称元素的数据* 参数:list - 目标顺序表指针;old - 要修改的元素名称;new - 新的数据* 返回值:0表示成功,非0表示失败(如未找到对应元素)*/
int ModifySeqList(SeqList *list, char *old, DATATYPE new);/** 删除顺序表中指定名称的元素* 参数:list - 目标顺序表指针;name - 要删除的元素名称* 返回值:0表示成功,非0表示失败(如未找到对应元素)*/
int DeleteSeqList(SeqList *list, char *name);/** 清空顺序表中的所有元素(保留表结构)* 参数:list - 要清空的顺序表指针* 返回值:0表示成功,非0表示失败*/
int ClearSeqList(SeqList *list);
相关函数:

代码示例

01typedef.c
typedef unsigned int u32_t; // 定义别名 
#include <string.h>typedef struct Per 
{char name[50];int age;char phone[50];
} PER;int main(int argc, char *argv[])
{u32_t a;  // 使用别名定义变量unsigned int b;  // 直接使用原始类型定义变量struct Per per;  // 使用原始结构体名strcpy(per.name, "zhangsan"); // 1000per.age = 20;PER p;  // 使用别名定义结构体变量return 0;
}

运行结果:程序正常编译运行,无输出

结构体的引用:①结构体的定义是变量的引用:(per.age)

                         ②结构体定义的是指针的引用:(per->ag)

内存泄露检测工具
sudo apt-get install valgrind
valgrind ./all

seqlist.h

.h:对应的头文件

目的:防止头文件重复包含带来的重复定义问题

格式:

#ifndef _SEQLIST_H_(文件名转换的)
#define _SEQLIST_H_(声明,宏定义)

#endif

#ifndef _SEQLIST_H_
#define _SEQLIST_H_typedef struct person
{char name[32];char sex;int age;int score;
} DATATYPE;typedef struct list
{// 数组指针(指针指向这个存储数据的连续内存:结构体(数组首元素))DATATYPE *head;//head:指向数据存储(DATATYPE)的指针,相当于动态数组的首地址// 数组的容量int tlen;// 数组的有效元素个数int clen;
} SeqList;// 创建顺序表
SeqList *CreateSeqList(int len);// 显示顺序表数据
int ShowSeqList(SeqList *list);// 顺序表尾插
int InsertTailSeqList(SeqList *list, DATATYPE *data);// 是否满
int IsFullSeqList(SeqList *list);// 是否空
int IsEmptySeqList(SeqList *list);// 按位置插入
int InsertPosSeqList(SeqList *list, DATATYPE *data, int pos);// 查找顺序表
int FindSeqList(SeqList *list, char *name);// 修改顺序表
int ModifySeqList(SeqList *list, char *old, DATATYPE *newdata);// 清空表
int ClearSeqList(SeqList *list);// 销毁顺序表
int DestroySeqList(SeqList *list);// 删除一个元素
int DeleteSeqList(SeqList *list, char *name);
//获得有效元素个数
int GetSizeSeqList(SeqList *list);DATATYPE* GetItemSeqlist(SeqList*list, int pos);#endif
seqlist.c
#include "seqlist.h"//包入自己写的头文件,用""引用
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
SeqList *CreateSeqList(int len)//创建顺序表
{SeqList *sl = malloc(sizeof(SeqList));  // 分配顺序表结构体内存//解释sizeof(Seqlist):包含数据存储空间和tlen,clenif (NULL == sl){perror("CreateSeqList malloc error\n");  // 内存分配失败处理return NULL;}sl->head = malloc(sizeof(DATATYPE) * len);  // 分配数据存储空间//解释sizeof(DATATYPE)*len:相当于有len(传入的个数)个DATATYPE数组if (NULL == sl->head){perror("CreateSeqList malloc2 error\n");  // 数据空间分配失败处理return NULL;}sl->tlen = len;  // 设置总长度sl->clen = 0;    // 初始化当前长度为0return sl;
//两个结构体的内存空间
}
//list->head:结构名指向结构体中的元素
int InsertTailSeqList(SeqList *list, DATATYPE *data)//顺序表尾插
{// list->head[list->clen] =*data;//list->clen代表顺序表的数据当前位置,当前位置的数组下标位置if (IsFullSeqList(list))  // 检查是否已满{printf("seqlist is full\n");  // 已满提示return 1;}/*list->head[list->clen]:表示当前顺序表位置sizeof(DATATYPE):表示DATATYPE结构体大小data是DATAYPE结构体类型*/memcpy(&list->head[list->clen], data, sizeof(DATATYPE));  // 复制数据到尾部list->clen++;  // 当前长度加1return 0;
}int IsFullSeqList(SeqList *list)//判断顺序表是否满
{return list->clen == list->tlen;  // 判断当前有效长度是否等于数组总容量
}int ShowSeqList(SeqList *list)//遍历顺序表中的数据
{int len = GetSizeSeqList(list);  // 获取当前元素个数int i = 0;for (i = 0; i < len; ++i){//解释list->head[i].name:顺序表名指向结构体元素head,但head(数组的首地址)为指针指向另一个结构体,继续指向结构体中的元素nameprintf("name:%s sex:%c age:%d score:%d\n", list->head[i].name,list->head[i].sex, list->head[i].age, list->head[i].score);};return 0;
}/*** @brief Get the Size Seq List object** @param list 被查询的顺序表* @return int  顺序表有效元素的个数*/
int GetSizeSeqList(SeqList *list)
{return list->clen;  // 返回当前元素个数
}int IsEmptySeqList(SeqList *list)//判断当前长度是否为0
{return 0 == list->clen;
}/*** @brief 按位置插入元素** @param list 待插入的顺序表* @param data  需要插入的数据* @param pos 顺序表的下标* @return int 0 表示成功 1表示失败*/
int InsertPosSeqList(SeqList *list, DATATYPE *data, int pos)//按位置(pos)插入元素
{if (IsFullSeqList(list))  // 检查是否已满{printf("seqlist is full\n");return 1;}int len = GetSizeSeqList(list);if (pos < 0 || pos > len)  // 检查位置是否合法{printf("pos is incorrect\n");return 1;}// 整体后移,让出位置for (int i = list->clen; i > pos; i--){// list->head[i] = list->head[i - 1];memcpy(&list->head[i], &list->head[i - 1], sizeof(DATATYPE));  // 后移元素}memcpy(&list->head[pos], data, sizeof(DATATYPE));  // 插入新元素list->clen++;  // 当前长度加1return 0;
}/*** @brief 按名字查找信息** @param list 待查询的顺序表* @param name 要查询的人员信息名字* @return int 成功的 0>=len-1 失败 -1*/
int FindSeqList(SeqList *list, char *name)
{int len = GetSizeSeqList(list);for (int i = 0; i < len; i++)  // 遍历查找{if (0 == strcmp(list->head[i].name, name))  // 比较名字{return i;  // 找到返回位置}}return -1;  // 未找到返回-1
}DATATYPE* GetItemSeqlist(SeqList*list, int pos)// 检查位置是否合法
{int len = GetSizeSeqList(list);if (pos < 0 || pos > len) {printf("pos is incorrect\n");return NULL;//返回值为指针类型}return &list->head[pos];  // 返回指定位置元素的指针
}int ModifySeqList(SeqList *list, char *oldname, DATATYPE *newdata)//修改元素
{int ret = FindSeqList(list, oldname);  // 查找要修改的元素if(-1 == ret)  // 未找到{printf("modify failure...\n");return 1;}memcpy(&list->head[ret], newdata, sizeof(DATATYPE));  // 修改数据return 0;
}// 清空表:原理:将数据重新定位到开头,用新的数据去覆盖
int ClearSeqList(SeqList *list)
{list->clen = 0;  // 将当前长度设为0return 0;
}// 销毁顺序表
int DestroySeqList(SeqList *list)
{free(list->head);  // 空间使用的是堆,需要释放数据存储空间free(list);        // 释放顺序表结构体return 0;
}
int DeleteSeqList(SeqList *list, char *name)//删除一个元素
{int pos=FindSeqList(list, name);//按名字查找if(-1==pos){printf("no found per %s\n",name);return -1;}//将该位置之后的说有元素向前移动一位int i=0;for (i=pos;i<list->clen-1;i++){memccpy(&list->head[i],&list->head[i+1],sizeof(DATATYPE));}list->clen--;//长度减一return 0;}

内存泄漏检测工具(命令):sudo apt-get install valgrind

编译:valgrind  ./all

堆的空间释放顺序:先释放head,在释放顺序表

main.c

#include<stdio.h>
#include<stdlib.h>
#include"seqlist.h"
int	main(int argc, char **argv)
{SeqList *s1=CreateSeqList(5);//创建一个顺序表DATATYPE data[] = {{"zhangsan", 'm', 20, 80},    // 定义测试数据{"lisi", 'f', 23, 84},{"wangmaizi", 'f', 32, 90},{"guanerge", 'm', 50, 91},{"liubei", 'm', 51, 92},};InsertTailSeqList(s1, &data[0]);  // 将data[i]中的数据尾部插入数据InsertTailSeqList(s1, &data[1]);    //dat[i]相当于代表二维数组一整排的元素,所以不用在指向data中的元素InsertTailSeqList(s1, &data[2]);InsertPosSeqList(s1,&data[2],1);ShowSeqList(s1);char want_name[20]="lisi";int ret=FindSeqList(s1, want_name);//找lisi的位置,并把位置放在ret中if(-1==ret){printf("can't find per %s\n",want_name);}else{DATATYPE *tmp=GetItemSeqlist(s1,ret);//检查位置在数据中是否合法printf("find per,%s %d\n",tmp->name,tmp->score);}ModifySeqList(s1,"list",&data[4]);//修改元素ShowSeqList(s1);//遍历DestroySeqList(s1);//删除顺序表//system("pause");return 0;
}
}


Makefile:工程管理工具(代替gcc用make编译)

1.第一个版本:

#目标名:依赖文件
#第二行的开头是一个tab
all:main.c seqlist.cgcc main.c seqlist.c -o all
clean://clean为清除,重新编译//命令 make cleanrm all

2.第二个版本:

#目标名:依赖文件
#第二行的开头是一个tab
#在一条规则中,$^代表依赖文件  $@代表规则中的目标名
#$^,$@都是Makefile的内部变量
all:main.c seqlist.cgcc $^ -o $@   #使用内部变量简化命令cp main.c 1.c  #添加复制命令
clean:rm all $^     # 删除可执行文件和源文件

3.第三个版本:(最终版本)

# .o 目标文件 
SRC= main.o  # 定义源文件列表
SRC+= seqlist.o
DST=all      # 定义目标文件名
CC=gcc       # 定义编译器
LIB= -lm     # 定义链接库%.o:%.c$(CC) -c $^ -o $@  # 编译规则:将.c文件编译为.o文件$(DST):$(SRC)$(CC) $^ -o $@ $(LIB)  # 链接规则:将.o文件链接为可执行文件clean:rm $(DST) *.o  # 清理规则:删除可执行文件和目标文件

文章转载自:

http://RgtRUf75.Lxfqc.cn
http://cTeuaDs3.Lxfqc.cn
http://Ur81edpU.Lxfqc.cn
http://EmNbkqQO.Lxfqc.cn
http://ZIeJQNO9.Lxfqc.cn
http://UhM3Mgyn.Lxfqc.cn
http://YTuoZ410.Lxfqc.cn
http://tFjSdf73.Lxfqc.cn
http://otNOxbta.Lxfqc.cn
http://Fw5JKML3.Lxfqc.cn
http://e5xhZacR.Lxfqc.cn
http://f3aXnlsb.Lxfqc.cn
http://qsdxjyZo.Lxfqc.cn
http://qVDT5SJ3.Lxfqc.cn
http://6UbRgXYr.Lxfqc.cn
http://bgPwH4XX.Lxfqc.cn
http://flEPnl0S.Lxfqc.cn
http://efnBQWEC.Lxfqc.cn
http://pPdMmm0z.Lxfqc.cn
http://fEsSrEhJ.Lxfqc.cn
http://doe8r232.Lxfqc.cn
http://4Watcjck.Lxfqc.cn
http://cDRasKqn.Lxfqc.cn
http://FiqfevT4.Lxfqc.cn
http://zl0dCfAt.Lxfqc.cn
http://rbevjbPq.Lxfqc.cn
http://RNEHYJLj.Lxfqc.cn
http://CwqvzwzY.Lxfqc.cn
http://WrVseuFh.Lxfqc.cn
http://ZlvImpCe.Lxfqc.cn
http://www.dtcms.com/a/372206.html

相关文章:

  • make_shared的使用
  • 《九江棒球》未来十年棒垒球发展规划·棒球1号位
  • agentscope1.0安装与测试
  • Shell 脚本自动安装 Nginx
  • 《探索C++11:现代语法的内存管理优化“性能指针”(下篇)》
  • Basic Pentesting: 1靶场渗透
  • NAS自建笔记服务leanote2
  • 对比Java学习Go——程序结构与变量
  • 【JavaWeb】一个简单的Web浏览服务程序
  • [C/C++学习] 7.“旋转蛇“视觉图形生成
  • webhook(Web 钩子)是什么?
  • 《2025年AI产业发展十大趋势报告》四十三
  • java面试小册(1)
  • NW506NW507美光固态闪存NW525NW539
  • [Maven 基础课程]再看下第一个 Maven 项目
  • Keil快捷键代码补全
  • 2024理想算法岗笔试笔记
  • Java面试-线程安全篇
  • 线程池深度解析:ThreadPoolExecutor底层实现与CompletableFuture异步编程实战
  • 计算机网络学习(七、网络安全)
  • 蓝奏云官方版不好用?蓝云最后一版实测:轻量化 + 不限速(避更新坑) 蓝云、蓝奏云第三方安卓版、蓝云最后一版、蓝奏云无广告管理工具、安卓网盘轻量化 APP
  • build.gradle里面dependencies compile和api的区别
  • C++20格式化字符串:std::format的使用与实践
  • UART 使用教程
  • cuda中线程id的计算方式(简单)
  • Archon02-代码解析
  • # 图片格式转换工具:重新定义您的图片处理体验
  • 【Python】S1 基础篇 P2 列表详解:基础操作
  • 液压伺服千斤顶系统设计cad+设计说明书
  • MySQL 锁机制解析