0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

链表的替代品--Vector组件

Rice嵌入式开发技术分享 来源: Rice嵌入式开发技术分 作者: Rice嵌入式开发 2023-04-06 15:39 次阅读

概述

  1. 优点:①链表上的元素在空间存储上内存地址不连续;②在插入和删除操作时,只需要修改被删节点上一节点的链接地址,不需要移动元素;
  2. 缺点:①没有解决连续存储分配带来的表长难以确定的问题;②失去了顺序存储结构随机存取的特性;③不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头节点开始遍历,直到找到为止。
  • SPEvent实际不会存在删改的动作,显然链表的优点在这个组件中无法体现优势。而实际顺利存储更能满足SPEvent的业务及能力,那么有什么方式能做到这个操作了?答案肯定是有的,有一个好组件(Vector)正好可以解决掉这个问题。
  • Vector组件--向量;这个名称一点也不陌生,比如我们单片机开发中常常听到中断向量表,它是通过地址查找对应中断服务函数;而Vector组件也有点类似这个概念,它可以通过名称、类型查找对象。
  • Vector组件的优势可以应用像SPEvent这类组件中,如:SPEvent就可以通过Event类型去查找事件节点。那么Vector是怎么实现的??

Vector组件

Vector组件--它是类似于链表拥有的能力,是一种动态数组存储组件,Vector组件拥有的能力如下:

  1. 提供了顺序存储的能力,并且能够动态增大顺序存储空间;
  2. 提供了增加对象能力,查找对象能力。
  3. 提供获取顺序存储空间能力,获取对象个数能力。
  4. 采用KEY-VALUE的特性开查找对象。

Vector接口说明:

接口 描述
Vector VECTOR_Make(VECTOR_Key key, VECTOR_Compare compare) 创建Vector列表对象,用户根据业务注册VECTOR_Key方法和VECTOR_Compare方法
void VECTOR_Clear(Vector *vector) 清空Vector列表对象,并释放存储数据空间
int16_t VECTOR_Add(Vector *vector, void *element) 添加元素到Vector列表对象
int16_t VECTOR_Size(Vector *vector) 获取Vector列表对象的元素个数
int16_t VECTOR_Num(Vector *vector) 获取Vector列表对象的元素记录数目
void *VECTOR_At(Vector *vector, int16_t index) 根据下标获取Vector列表对象的元素
void *VECTOR_Swap(Vector *vector, int16_t index, void *element) 替换指定下标的Vector列表对象的元素
int16_t VECTOR_Find(Vector *vector, const void *element) 通过元素从Vector列表对象中查找对应下标
int16_t VECTOR_FindByKey(Vector *vector, const void *key) 通过键从Vector列表对象中查找对应下标

Vector实现:

  • 数据结构:每一个存储列表都需要构造一个Vector结构体对象,用于存储元素对象。
//vector.h
#defineGROW_STEP4

#defineINVALID_INDEX(-1)
typedefvoid*(*VECTOR_Key)(constvoid*);//应用层提供KEY-VALUE获取方法,泛类型
typedefint(*VECTOR_Compare)(constvoid*,constvoid*);//应用层提供比较函数,泛类型

typedefstructSimpleVector{
int16_tmax;//vector所能存储的最大数据记录数目
int16_ttop;//vector当前已经存储的数据的峰值数目
int16_tfree;//vector已经被释放的数据记录数目
void**data;//vector存储数据指针
VECTOR_Keykey;//将数据元素转换为用于比较的键。方法由用户提供
VECTOR_Comparecompare;//将用于比较键值。方法由用户提供
}Vector;
  • Vector列表对象构造方法:其中max,top,free初始状态都为0。
VectorVECTOR_Make(VECTOR_Keykey,VECTOR_Comparecompare)
{
Vectorvector={0,0,0,NULL,key,compare};
returnvector;
}
  • Vector列表对象清除方法:将Vector列表对象的数据元素空间释放,并将max,top,free清0。
voidVECTOR_Clear(Vector*vector)
{
if(vector==NULL){
return;
}
if(vector->data==NULL){
return;
}
free(vector->data);
vector->max=0;
vector->top=0;
vector->free=0;
vector->data=NULL;
}
  • Vector列表对象增加元素方法:
    • 存储方式:采用顺序存储方式
    • 存储空间扩展策略:通过GROW_STEP的来决定没存储多少个元素来动态扩展空间;描述:如GROW_STEP的值为4,每次申请4个空间进行存储,如果存储元素个数小于4个,不会重新申请空间;如果元素个数个数超过4个,那么将重新申请4个空间。以此类推。优点:减少每次增加元素都要重新申请空间,提高了效率。
int16_tVECTOR_Add(Vector*vector,void*element)
{
if(vector==NULL||element==NULL){
returnINVALID_INDEX;
}

if(vector->top>=vector->max){
int16_ti;
for(i=vector->top-(int16_t)1;i>=0;--i){
if(vector->data[i]==NULL){
vector->data[i]=element;
vector->free--;
returni;
}
}

if(vector->max+GROW_STEP< 0){
returnINVALID_INDEX;
}

void**data=(void**)malloc(sizeof(void*)*(vector->max+GROW_STEP));
if(data==NULL){
returnINVALID_INDEX;
}

if(vector->data!=NULL){
(void)memcpy(data,vector->data,sizeof(void*)*vector->max);
free(vector->data);
}
vector->data=data;
vector->max+=GROW_STEP;
}

vector->data[vector->top]=element;
returnvector->top++;
}
  • Vector列表对象根据下标过去对象方法:Vector可以直接通过顺序表的策略,直接通过下标获取元素;相对于链表来说,效率更加有优势。
void*VECTOR_At(Vector*vector,int16_tindex)
{
if(vector==NULL||vector->top<= index || index < 0){
returnNULL;
}

returnvector->data[index];
}
  • Vector列表对象根据下标替换对象方法:Vector可以直接通过顺序表的策略,直接通过下标修改元素;相对于链表来说,效率更加有优势。
void*VECTOR_Swap(Vector*vector,int16_tindex,void*element)
{
if(vector==NULL||vector->top<= index || index < 0){
returnNULL;
}
if(element==NULL){
vector->free++;
}
void*oldElement=vector->data[index];
vector->data[index]=element;
returnoldElement;
}
  • Vector列表对象根据元素查找对应下标方法:最终也是调用VECTOR_FindByKey方法。
int16_tVECTOR_Find(Vector*vector,constvoid*element)
{
if(vector==NULL||element==NULL){
returnINVALID_INDEX;
}
returnVECTOR_FindByKey(vector,(vector->key==NULL)?element:vector->key(element));
}
  • Vector列表对象根据键查找对应下标方法:遍历整个Vector列表,查询对应的key值,并返回对应下边。
int16_tVECTOR_FindByKey(Vector*vector,constvoid*key)
{
if(vector==NULL||key==NULL){
returnINVALID_INDEX;
}

int16_ti;
for(i=0;i< vector->top;++i){
if(vector->data[i]==NULL){
continue;
}

void*first=(vector->key!=NULL)?vector->key(vector->data[i]):vector->data[i];
if(first==key){
returni;
}

if(vector->compare==NULL||first==NULL){
continue;
}

if(vector->compare(first,key)==0){
returni;
}
}
returnINVALID_INDEX;
}
  • Vector列表对象中元素个数获取方法:
int16_tVECTOR_Size(Vector*vector)
{
if(vector==NULL){
returnINVALID_INDEX;
}
returnvector->top;
}
  • Vector列表对象中元素记录数目获取方法:
int16_tVECTOR_Num(Vector*vector)
{
if(vector==NULL){
returnINVALID_INDEX;
}
returnvector->top-vector->free;
}

Vector使用:

  1. 定义一个元素结构体(vector_test),包含两个字段:name和data,其中name可以作为元素对象的唯一标识。

  2. 定义两个vector_test变量,test1和test2。

  3. 我们这个demo是采用name作为唯一标识,需要顶一个函数用于获取vector_test变量的name字段成员的值,作为VECTOR_Key指向函数。

  4. 通过VECTOR_Make构造一个vector对象。其中VECTOR_Key指向vector_name_get函数作为key获取,VECTOR_Compare指向strcmp函数用于key(name字符串)的比较。

  5. 通过VECTOR_Add向vector对象增加元素test1和test2。

  6. 通过VECTOR_FindByKey从vector对象查找元素对象下标。如:key为"rice"的元素对象下标。

  7. 通过VECTOR_FindByKey获取的pos,调用VECTOR_At获取元素对象。

  8. 验证:根据获取元素对象调用其成员,确定是否成功。

#include"vector.h"

Vectorvector;

typedefstruct{
char*name;
intdata;
}vector_test;

vector_testtest1={"rice",100};
vector_testtest2={"chen",100};

constchar*vector_name_get(vector_test*test)
{
returntest->name;
}

intmain(void)
{
vector=VECTOR_Make(vector_name_get,strcmp);

VECTOR_Add(&vector,&test1);
VECTOR_Add(&vector,&test2);

int16_tpos=VECTOR_FindByKey(&vector,"rice");

printf("pos:%drn",pos);

vector_test*temp=VECTOR_At(&vector,pos);

printf("name:%srn",temp->name);

returnRT_EOK;
}
  • 结果:
a9699a96-cd3b-11ed-a826-dac502259ad0.png

欢迎关注微信公众号『Rice嵌入式开发技术分享』

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 嵌入式开发
    +关注

    关注

    18

    文章

    1019

    浏览量

    47486
  • 组件
    +关注

    关注

    1

    文章

    504

    浏览量

    17792
  • Vector
    +关注

    关注

    3

    文章

    54

    浏览量

    8545
收藏 人收藏

    评论

    相关推荐

    LM3080N的替代品有哪些?

    有这个芯片LM3080N的替代品没? 帮人询问呢。谢谢。
    发表于 09-14 08:46

    寻找松下TX2-12V的替代品

    松下的效益不行了,要搬场,继电器要涨价,求替代品。哪位大侠可以帮助一下。谢谢。原来用的型号是TX2-12V。附件中是他的数据手册。
    发表于 11-17 11:42

    寻求Ubuntu13系统下软件替代品……

    下的kile软件的替代品是什么?我在ubuntu软件中心找到了一个kile,但是安装后总感觉什么都没有,模板也找不到,完全不会用,球大神给讲解下……还有,Visual Studio的替代品,做fpga
    发表于 10-26 10:06

    如何寻找芯片IS61LV51216的替代品

    贴片,44脚的IS61LV51216是一个8M容量,结构为512K*16位字长的高速率SRAM,它的替代品有?码库网上没查到呀?怎么去找呢?
    发表于 05-17 17:34

    MMBFJ176替代品??

    如题,需要寻找一个MMBFJ176替代品,用于保证电化学检测器在断电的情况下两端电位不会偏差太大。附件为MMBFJ176规格书,望大神回复下,谢谢!
    发表于 07-21 08:33

    请问仪表放大器AD624有没有便宜的完全兼容的替代品

    仪表放大器AD624有没有便宜的完全兼容的替代品?市场上这个芯片有点贵,还不太好买到,想找兼容替代品,性能稍低点也可以,能满足要求就行,求大神推荐,谢谢。
    发表于 01-23 09:27

    是否有TDA2003的替代品

    是否有TDA2003的替代品,或者任何人都可以推荐类似的音频放大器,可以驱动低至1欧姆的负载? #TDA2003
    发表于 08-05 10:19

    如何使用ISP1763作为替代品

    已经过时,ST-Ericson提供的下一个系列是ISP1763。 ISP1760采用128引脚配置,具有16地址线和32数据线。但新的ISP1763只是64引脚,有8个地址和32个数据引脚。我们如何使用ISP1763作为替代品?这有什么替代方案吗?-谢谢
    发表于 09-04 07:00

    Commodore 6540 ROM的替代品

    的 6540 ROM 芯片组的直接替代品。我发现 D'Asaro 项目非常好且紧凑,但更难构建。此外,他仅以 PCBexpress 格式发布该项目,无法将其导出到 Gerber。由于
    发表于 09-02 07:26

    MC908JL3ECDWE的替代品是什么?

    我正在寻找 8 位 MCU MC908JL3ECDWE 的替代品,因为不建议将其用于新设计(已过时)。为了最大限度地减少工作量,我们希望减少对 28 引脚 SOIC 封装的替换和简单的代码更改
    发表于 06-05 06:17

    钴镍锰(三元)正极材料---钴酸锂的理想替代品

    钴镍锰(三元)正极材料---钴酸锂的理想替代品  钴镍锰(三元)正极材料---钴酸锂的理想替代品 产品特点
    发表于 10-29 11:59 2150次阅读

    最佳 CPU 导热膏替代品替代品

    CPU导热膏之于装配工和电脑维修工,线程之于时装设计师。这强调了这种维修工具的重要性,以及为什么必须有足够的供应来加强他们的工作。但是,当意外发生时,有可用的替代品,可以守住堡垒。 很多时候,组装商
    的头像 发表于 07-27 16:10 6550次阅读
    最佳 CPU 导热膏<b class='flag-5'>替代品</b>和<b class='flag-5'>替代品</b>

    链表替代品Vector组件介绍

    SPEvent实际不会存在删改的动作,显然链表的优点在这个组件中无法体现优势。
    的头像 发表于 03-07 10:41 669次阅读

    变速泵的更好电机替代品

    变速泵的更好电机替代品(视频)
    的头像 发表于 03-13 17:02 749次阅读
    变速泵的更好电机<b class='flag-5'>替代品</b>

    CFP – SMx封装的高效替代品

    CFP – SMx封装的高效替代品
    的头像 发表于 12-05 10:58 639次阅读
    CFP – SMx封装的高效<b class='flag-5'>替代品</b>