数据结构:顺序表图解及c代码

在这里插入图片描述
顺序表思想
定义了一个顺序表的结构体,存放了它的长度,容量信息,还有申请的存结点的内存的首地址。

结构体中定义的是一个二级指针,申请的内存是存放传入结点的指针。

内存管理方面:顺序表管理指表内存和指针数组内存。
结点的内存由上层自己负责。

seqlist.h

#ifndef SEQLIST_H
#define SEQLIST_H

typedef void SeqList;
typedef void SeqListNode;

SeqList* SeqList_Create(int capacity);

void SeqList_Destroy(SeqList* list);

void SeqList_Clear(SeqList* list);

int SeqList_Length(SeqList* list);

int SeqList_Capacity(SeqList* list);

int SeqList_Insert(SeqList* list, SeqListNode *node,int pos);

SeqListNode* SeqList_Get(SeqList *list,int pos);

SeqListNode* SeqList_Delete(SeqList* list ,int pos);

#endif // SEQLIST_H
typedef void SeqList;
typedef void SeqListNode;

传给上层的是一个void类型,对于他们来说只是一个句柄,留给上层管理表的首地址以及结点地址。
上层测试中

Teacher* tmp = (Teacher *)SeqList_Get(list, i);

根据自己的业务来解析表传来的结点地址

上层将顺序表地址和结点地址传给底层函数,底层函数知道具体类型是什么,类型转换后进行操作与处理。
所以在seqlist.c中,每个函数中都有两句代码。

  TSeqList *tlist = NULL;
  tlist = (TSeqList*)list;

seqlist.c

定义表的结构体

typedef struct _tag_SeqList
{
    int length;
    int capacity;
    unsigned int **node;
}TSeqList;

创建表时
1.要申请表的内存,内存清零
2.根据容量申请相应的内存来存放结点指针,node 是二级指针,node[i]是指针。
3.参数置初始状态

SeqList* SeqList_Create(int capacity)
{
    int ret =0;
    TSeqList *tmp = NULL;
    tmp=(TSeqList*)malloc(sizeof(TSeqList));
    if(tmp == NULL)
    {
        ret = -1;
        printf("func SeqList_Create() err:create %d\n",ret);
        return NULL;
    }
    memset(tmp,0,sizeof(TSeqList));   //需要包含string.h头文件
    tmp->node=(unsigned int **)malloc(sizeof(unsigned int *)*capacity);
    //这里顺序表只是存了结点的地址以保证能访问,但是不把节点数据及内存并入顺序表中
    //这样顺序表只管理自己申请的这俩内存,而节点的内存还是由上层管理
    //这也是destroy中只用释放申请的tlist->node及tlist本身的内存
    if(tmp->node == NULL)
    {
        ret = -2;
        printf("func SeqList_Create() err:malloc %d\n",ret);
        return NULL;
    }
    tmp->capacity = capacity;
    tmp->length = 0;
     return tmp;
}

顺序表销毁时要释放内存
顺序表清空时主要是长度要置零以重新存数据。
这里可加memset? 我觉得是要加,主动清零内存

void SeqList_Destroy(SeqList* list)
{
    TSeqList *tlist = NULL;
    if(list == NULL)
    {
        return ;
    }
    tlist = (TSeqList*)list;
    if(tlist->node!=NULL)
    {
        free(tlist->node);
    }
    free(tlist);
    return;

}
void SeqList_Clear(SeqList* list)
{
     TSeqList *tlist = NULL;
     if(list == NULL)
     {
        return ;
     }
     tlist= (TSeqList*)list;
     //memset(tlist->node,0,sizeof(unsigned int *)*tlist->capacity);
     tlist->length = 0;
     return;
}

获取长度和容量没什么,返回数据就可以

int SeqList_Length(SeqList* list)
{
    TSeqList *tlist = NULL;
    if(list == NULL)
    {
        return -1;
    }
    tlist = (TSeqList*)list;
    return tlist->length;
}
int SeqList_Capacity(SeqList* list)
{
    TSeqList *tlist = NULL;
    if(list == NULL)
    {
        return -1;
    }
    tlist = (TSeqList*)list;
    return tlist->capacity;
}

获取结点也不涉及移动,直接返回相应位置的节点即可

SeqListNode* SeqList_Get(SeqList *list,int pos)
{
     int i =0,ret =0;
     TSeqList *tlist = NULL;
     SeqListNode *s_ret = NULL;
     if(list == NULL || pos <0)
     {
        ret = -1;
        printf("funt SeqList_Get() err %d\n",ret);
        return NULL;
     }
     tlist = (TSeqList*)list;
     s_ret =(SeqListNode*)tlist->node[pos];
     return s_ret;
}

插入和删除一个是要移动, 二是要注意长度++或 - -,同时要判断位置是否合法,判满等。

int SeqList_Insert(SeqList* list, SeqListNode *node,int pos)
{
    int i =0,ret =0;
    TSeqList *tlist = NULL;
    if(list == NULL || node == NULL || pos <0)  //为什么不判pos>length呢? 因为只要表没满,可以处理让他插在最尾
    {
        ret = -1;
        printf("func SeqList_Insert() err %d\n",ret);
        return ret;
    }
    tlist = (TSeqList*)list;
    //先判满
    if(tlist->length == tlist->capacity)
    {
        ret = -2;
        printf("func SeqList_Insert() (tlist->length == tlist->capacity) err: %d\n",ret);
        return ret;
    }
    //容错修正
    if(pos>tlist->length)
    {
        pos = tlist->length;
    }
    //先后移元素
    for(i=tlist->length;i>pos;i--)
    {
        tlist->node[i]=tlist->node[i-1];
    }
    tlist->node[i] = node;
    tlist->length++;
    return 0;
}
SeqListNode* SeqList_Delete(SeqList* list ,int pos)
{
    int i=0;
    TSeqList *tlist = NULL;
    SeqListNode *ret = NULL;
    if(list == NULL || pos < 0)   //删除位置大于表长度的情况如何处理,返回的是NULL
    //但存在clear后未覆盖删除原有数据的问题吧?所以应优化clear
    {
        printf("func SeqList_Delete() err");
        return NULL;
    }
    tlist = (SeqList*)list;
    ret = (SeqListNode*)tlist->node[pos];
    for(i=pos+1;i<tlist->length;i++)
    {
        tlist->node[i-1]=tlist->node[i];
    }
    tlist->length--;
     return ret;
}

插入操作时要先判满和容错修正,然后移动,再插入
删除操作时先缓存要弹出的结点,再移动。返回结点

测试用例

    ret = SeqList_Insert(list, (SeqListNode*)&t5, 0);  //头插法

    for (int i = 0; i < SeqList_Length(list); i++)
    {
    Teacher* tmp = (Teacher *)SeqList_Get(list, i);
        if (tmp == NULL)
        {
            return;
        }
        printf("tmp->age:%d", tmp->age);
    }

一个是头插法。 数据可以传入结构体等类型
再一个是解析弹出的结点,根据上层的数据类型进行类型转换后解读。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值