数据结构之顺序表的模拟实现

本文详细介绍顺序表的基本概念、实现原理及各种操作方法,包括初始化、增删改查等功能的实现细节。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

顺序表

顺序表:用一段地址连续的存储单元依次存储数据元素的线性结构,地址连续的空间,一般情况下采用数组,但数组有静态数组和动态数组,所以顺序表分为:静态顺序表和动态顺序表。

要模拟顺序表,那么我们就要清楚顺序表有哪些功能。
首先顺序表可以对其内容进行增删改。所以我们就要考虑到如何对其进行增删改,以及在不同情况下不同的应对方式。


接下来我们说说模拟顺序表的思路。
首先,既然是顺序表,那么我们可以用数组来模拟实现,再者为了代码的可读性强,并且修改调整性好我们来定义一个结构体来达到这一目的。

#define char Seqtype

#include <stddef.h>

#define SeqListMax 1000

typedef struct SeqList{
    Seqtype data[SeqListMax];
    size_t size;
}SeqList; 

这里我们先定义一个结构体类型SeqList便于后面对结构体的操作访问等。然后定义了顺序表的大小用SeqListMax表示,用Seqtype来定义顺序表内内容的类型char,然后用一个szie_t也就是无符号长整形来定义这个顺序表内容的个数,来防止意外溢出的问题。接下来,我们就要开始对这个顺序表进行实现了。


我们先将这个顺序表的框架进行搭建

#define char Seqtype

#define SeqListMax 1000

typedef struct SeqList{
    Seqtype data[SeqListMax];//利用宏来定义这个数组大小,便于以后的扩展缩小等
    size_t size;//利用无符号长整型来防止意外溢出的情况,基本上足够用了,不太可能溢出
}SeqList;//定义顺序表结构体

基本所需要的都已经定义出来,接下来就是顺序表的结构框架的搭建

void SeqListPrint(SeqList* seqlist);//顺序表的打印。首先,我们在整个过程中,必须不断的测试我们的代码,而打印顺序表正是测试的好方法,所以顺序表的打印必不可缺
//实现
void SeqListPrint(SeqList* seqlist)
{
    if( NULL == seqlist)
    {
        return;//传过来指针首先就应该判断是否为空,才能有后续的操作,后面不再注释
    }
    size_t i = 0;
    for( ; i < seqlist->size; ++i)
    {
        printf("[%c] ",seqlist->data[i]);//打印顺序表内容,即数组内容
    }
    printf("\n");
}


void SeqListInit(SeqList* seqlist);//顺序表的初始化
//顺序表初始化,只需要将顺序表的元素个数设置为零即可
//实现
void SeqListInit(SeqList* seqlist)
{
    if( NULL == seqlist)
    {
        return;
    }

    seqlist->size = 0;
}

在实现了对顺序表初始化以及打印之后,接下来就到了对顺序表内部元素进行操作的实现了,对顺序表内元素操作,包括增加元素、删除元素、查找元素、修改元素等几个方面。我们逐步分块实现。


对顺序表尾部插入、删除元素

void  SeqListPushBack(SeqList* seqlist, Seqtype value);//尾部插入

尾部插入:应该先判断顺序表是否已满, 若顺序表已满,则打印该顺序表已满,然后直接return,若顺序表没有满,则将顺序表总大小加一,并在最后的位置插入想要插入的元素即可。

//实现
void SeqListPushBack(SeqList* seqlist, Seqtype value);//尾部插入
{
    if( NULL == seqlist)
    {
        return;
    }
    if( seqlist->size >= SeqListMax)
    {
        printf("顺序表已满\n");
    }
    ++seqlist->size;
    seqlist->data[seqlist->size-1] = value;//插入到尾部
}
void SeqListPopBack(SeqList* seqlist, Seqtype value);//尾部删除

尾部删除:首先先判断该顺序表是否为空顺序表,若为空顺序表直接返回,并打印该顺序表为空表无须删除,若顺序表不是空表,则将顺序表的总元素个数减一,即可删除最后一个元素

//实现
void SeqListPopBack(SeqList* seqlist, Seqtype value)
{
    if( NULL == seqlist)
    {
        return;
    }
    if( 0 == seqlist->size)
    {
        printf("该顺序表为空顺序表\n");
        return;
    }
    --seqlist->size;//尾部删除
}

对顺序表头部插入、删除元素

void SeqListPushFront(SeqList* seqlist, Seqtype value);//头部插入

头部插入:在顺序表头部插入元素时,首先应判断顺序表是否已满,若已满,直接打印该顺序表已满,并return;若没有满,则将顺序表内总元素个数加一腾出一个空位置,然后再将最后一个元素赋值给空位置,以此类推,直至将第一个元素赋值完成后,再将要插入的元素赋给第一个位置即可。如下图;
这里写图片描述

//实现
void SeqListPushFront(SeqList* seqlist, Seqtype value)//头部插入
{
    if( NULL == seqlist)
    {
        return;
    }
    if( seqlist->size >= SeqListMax)
    {
        printf("顺序表已满\n");
        return;
    }
    ++seqlist->size;
    size_t i = size - 1;
    for( ; i > 0; --i)
    {
        seqlist->data[i] = seqlist->data[i-1];
    }
    seqlist->data[0] = value;//头部插入
}
void SeqListPopFront(SeqList* seqlist);//头部删除

头部删除:在进行头部删除之前,首先应该判断该顺序表是否为空表,如果为空表,则打印该顺序表为空表,并且return。若不为空表,那么从顺序表第二个元素开始,向前一个元素进行覆盖,以此类推,最后再将顺序表总大小减一即可。
如下图;
这里写图片描述

//实现
void SeqListPopFront(SeqList* seqlist, Seqtype value)//头部删除
{
    if( NULL == seqlist)
    {
        return; 
    }
    if( 0 == seqlist->size)
    {
        printf("该顺序表为空顺序表\n");
    }
    size_i = 0;
    for( ; i < seqlist->size; ++i)
    {
        seqlist->data[i] = seqlist->data[i+1];
    }
    --seqlist->size;
}

在顺序表任意位置插入、删除元素

//任意位置插入
void SeqListInsert(SeqList* seqlist, size_t pos, Seqtype value);

任意位置插入:插入之前先判断顺序表是否已满,若顺序表已满,则直接打印顺序表已满,并直接return;接着还要判断插入位置是否合法,若不合法,则打印插入位置越界。如果pos等于0,相当于头部插入,直接调用头部插入的即可。等到所有判断完之后,再进行插入,将顺序表总大小加一,再顺序表尾部开始,将前一个元素的内容赋给后面的,以此类推,直至pos位置,再将要插入的元素赋给pos即可,如下图:
这里写图片描述

//实现
//pos位置插入
void SeqListInsert(SeqList* seqlist, size_t pos, Seqtype value)
{
    if( NULL == seqlist)
    {
        return;
    }
    if( seqlist->size >= SeqListMax)
    {
        printf(""顺序表已满\n);
        return;
    }   
    if( pos > seqlist->size)
    {
        printf("插入元素越界\n");
        return;
    }
    if ( 0 == pos)
    {
        SeqListPushBack(seqlist, value);
        return;
    }
    ++seqlist->size;
    size_t i = seqlist->size-1;
    for( ; i-1 >= pos; --i)
    { 
        seqlist->data[i] = seqlist->data[i-1];
    }
    seqlist->data[pos] = value;
}
//任意位置删除
void SeqListErase(SeqList* seqlist, size_t pos);

任意位置删除:在删除之前应该先判断顺序表是否为空,若为空,直接提示并return,接着再判断删除位置是否合法,不合法的话提示并return,最后再进行删除。删除的时候,从pos位置开始,将后一个元素覆盖到前一个元素,以此类推,直至到最后一个,然后再将顺序表总元素减一即可。
这里写图片描述

//实现
//在pos位置删除
void SeqListErase(SeqList* seqlist, size_t pos)
{
    if( NULL == selist)
    {
        return;
    }
    if( 0 == seqlist->size)
    {
        printf("该顺序表为空顺序表\n");
    }
    if( pos >= seqlist->size)
    {
        printf("删除越界\n");
    }
    size_t i = pos;
    for( ; i+1 < seqlist->size; ++i)
    {
        seqlist->data[i] = seqlist->data[i+1];  
    }
    --seqlist->size;
}

在顺序表中读取pos位置元素

//读取pos位置元素
void SeqListRead(SeqList* seqlist, size_t pos, Seqtype* value);

读取pos位置元素:读取之前先判断读取是否合法,若不合法直接提示并return,合法直接打印即可。

//实现
int SeqListRead(SeqList* seqlist, size_t pos)
{
    if( NULL == seqlist)
    {
        return;
    }
    if( pos >= seqlist->size)
    {
        return -1;
    }
    *value = seqlist->data[pos];
    return 1;

在顺序表中修改pos位置元素

//修改pos位置元素
void SeqListChange(SeqList* seqlist, size_t pos, Seqtype value);

修改pos位置元素:修改之前判断pos位置是否合法,若不合法,直接提示并return,若合法将value直接覆盖到pos位置即可。

//实现
void SeqListChange(SeqList* seqlist, size_t pos, Seqtype value)
{
    if( NULL == seqlist)
    {
        return;
    }
    if( pos >= seqlist->size)
    {
        printf("修改位置越界\n"); 
        return;
    }
    seqlist->data[pos] = value;
}

在顺序表中查找指定元素

//查找指定元素
size_t SeqListFind(SeqList* seqlist, Seqtype value);

查找指定元素:遍历整个顺序表,如果查到元素则返回元素下标,若未查到返回-1.

//实现
size_t SeqListFind(SeqList* seqlist, Seqtype value)
{
    if( NULL == seqlist)
    {
        return;
    }

    size_t pos = 0;
    for( ; pos < seqlist->size; ++pos)
    {
        if(seqlist->data[pos] == value)
        {
            return pos;
        }
    }
    return -1;
}

在顺序表中删除value,只删除第一次出现的

//在顺序表中删除value,只删除第一次出现的
void SeqListRemove(SeqList* seqlist, Seqtype value);

实现这个功能我们可以利用之前的代码来实现。

//实现
void SeqListRemove(SeqList* seqlist, Seqtype value)
{
    if( NULL == seqlist)
    {
        return;
    }
    size_t pos = SeqListFind(seqlist,value);//先利用Find函数找到
    SeqListErase(seqlist,pos);//利用Erase函数删除
}

在顺序表中删除所有value

//删除所有value
void SeqListRemoveAll(SeqList* seqlist, Seqtype value);

要删除所有,只需要利用Find找到,然后逐次删除即可。

//实现
void SeqListRemoveAll(SeqList* seqlist, Seqtype value)
{
    if( NULL == seqlist)
    {
        return;
    }
    size_t i = 0;
    for( ; i < seqlist->size; ++i)
    {
        if( seqlist->data[i] == value)
        {
            SeqListErase(seqlist,i);
            i--;
        }
    }
}

冒泡排序顺序表内元素

void SeqListBubbleSort(SeqList* seqlist);

只需要写一个简单的排序代码即可

//实现
void Swap(Seqtype a, Seqtype b)
{
    Seqtype tmp = a;
    a = b;
    b = tmp;
}

void SeqListBubbleSort(SeqList* seqlist)
{
    if( NULL == seqlist)
    {
        return;
    }
    size_t count = 0;
    for( ; count < seqlist->size; ++count)
    {
        size_t cur = 0;
        for( ; cur < seqlist->size-1-count; ++cur)
        {
            if( seqlist->data[cur] > seqlist->data[cur+1])
            {
                Swap(&seqlist->data[cur],&seqlist->data[cur+1]);
            }
        }
    }
}

升级版冒泡排序,可控制升序降序,利用回调函数

typedef int (*Cmp)(Seqtype a, Seqtype b);
void SeqListBubbleSortEX(SeqList* seqlist, Cmp cmp);
//实现
int Greater(Seqtype a, Seqtype b)
{
    return a>b?1:0;
}
int Less(Seqtype a, Seqtype b)
{
    return a<b?1:0;
}
void Swap(Seqtype a, Seqtype b)
{
    Seqtype tmp = a;
    a = b;
    b = tmp;
}

void SeqListBubbleSortEX(SeqList* seqlist, Cmp cmp)
{
    if( NULL == seqlist)
    {
        return;
    }
    size_t count = 0;
    for( ; count < seqlist->size; ++count)
    {
        size_t cur = 0;
        for( ; cur < seqlist->size-1-count; ++cur)
        {
            if(cmp(seqlist->data[cur],seqlist->data[cur+1]))//利用一个函数指针指向一个函数来控制排序的升序降序。
            {
                Swap(&seqlist->data[cur],&seqlist->data[cur+1]);
            }
        }
    }
}

欢迎大家共同讨论,如有错误及时联系作者指出,并改正。谢谢大家!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值