顺序表(C语言)

目录

1.前言

2.静态顺序表

3.动态顺序表


1.前言

在学习顺序表之前,我们不妨先来了解一下线性表的概念

线性表是n个具有相同特征数据元素的有限序列。

属于是非常的简单,值得一提的是顺序表,链表都是线性表,下面,我们直接来进入关于顺序表的学习 。

对于顺序表我们可以这么来理解,既,用一个结构体来存储一组数据。

我们先来看第一种

2.静态顺序表

顾名思义,静态顺序表就是一个可存储的元素个数固定的顺序表,他的定义可用如下表示

#define N 10
struct SeqList
{
    int a[N];
    int size;
};

当然,这样太麻烦了,所以我们一般会一些重命名来简化代码

#define N 10
typedef int SLDatetype;


struct SeqList
{
    SLDatetype a[N];
    int size;
};

这样书写的话,如果我们以后想要更改顺序表中的数据类型的话,只要更改typedef就可以了。

其实,上面这种静态的写法应用甚少,所以我们经常采用更加灵活的动态写法,动态顺序表就是顺序表中的元素最大个数可以发生变化的顺序表。

它的定义如下

3.动态顺序表

typedef int SLDatetype;

struct SeqList
{
    SLDatetype* a;
    int size;//已经存储的元素个数
    int capacity;//最大可存储的元素个数
};

 因为动态的我们需要确定是否满了,所以需要一个容量来确定表示的变量,当然这里可以用柔性数组,但是没必要,柔性数组的应用不在这。

为了简化代码,我们可以多用几个typedef简写

typedef int SLDatetype;

typedef struct SeqList
{
    SLDatetype* a;
    int size;//已经存储的元素个数
    int capacity;//最大可存储的元素个数
}SL;

然后,到这里我们不难发现,在这个结构体中的指针a等一些数据都还没初始化,所以我们要写一个初始化化函数,来给我们的顺序表进行一个初始化。

void SLInit(SL* psl)
{
    SLDatetype* temp = (SLDatetype*)malloc(4*sizeof(SLDatetype));//在这里我们先开辟四个空间
    if(temp==NULL)
    {
        perror("malloc error");
        return;
    }
    psl = temp;
    psl->size = 0;
    psl->capacity = 4;

}

通过以上代码,我们完成了简单的初始化。

然后,我们要注意的是,我们在顺序表中开辟的空间使用malloc开辟的,所以需要我们手动释放,因此,我们需要写一个销毁函数,来处理我们使用完之后的顺序表

void SLDestory(SL* psl)
{
    free(psl->a);
    psl->a = NULL;
    psl->size =0;
    psl->capacity = 0;

}

这样的话就完成了对顺序表的销毁,下面呢,我们继续来写一个顺序表的尾插,但是呢,在进行尾插之前,我们应该先检查顺序表中的元素容量是否足够让我们插入一个元素,因此,我们最好先写一个检查容量并且可以扩充顺序表大小的函数

void SLCheckCapcity(SL* psl)
{
    if(psl->size == psl->capcity)
    {
        SLDateType* temp = (SLDateType*)relloc(pls->a,psl->capacity*2*sizeof(SLDateType));
        if(temp==NULL)
        {
            perror("relloc error");
            return;
        } 
        psl->a = temp;
        psl->capacity *= 2;
    };
}

 然后,我们就可以写在尾部插入数据的函数了,这个非常的简单,我就直接上代码了

void SLPushBack(SL* psl,SLDateType x)
{
    SLCheckCapcity(psl);
    psl->a[size]=x;
    psl->size++;
}

然后是头部插入,值得注意的是,因为顺序表用一个结构体中的指针来存储的,所以顺序表的本质就类似于一个数组,我们如果想在顺序表的头部存储一个元素的话,只能将所有的数据后移一个单位,然后再将数据插入到第一个位置。

下面来看一下代码的实现

void SLPushFront(SL* psl,SLDateType x)
{
    SLCheckCapcity(psl);
    int i =psl->size;
    while(i>0)
    {
        psl->a[i]=psl->a[i-1];
        i--;
    }
    psl->a[0]=x;
    ps->size++;
}

当然,写法不唯一,我这里只展示一种可行的代码。

其实在这里,我们就发现了,头插好像不太适合顺序表。所以说,其实每种数据结构都有他的局限性存在。

然后,我们再来看一下尾部删除,大家先想一下,尾部删除有必要把我要删除的那一个数据给改变成零或者进行其他的操作吗?

其实是不需要的,我们只需要类比一下free的原理,将我们要删除的数据的权限返还给操作系统就好了,因此,实现代码如下

void SLPopBack(SL* psl)
{
   psl->size--;
}

然后呢,我们来继续实现一下头部删除的函数,我们在删除头部的一个数据之后,还需要将后面所有的数据想前移动一个单位,所以,直接来看代码就好了。

void SLPopFront(SL* psl)
{
    int i =0;
    while(i<psl->capcity-1)
    {
        psl->a[i] = psl->a[i+1];        
        i++;
    }
   psl->size--;
}

看到这里,细心的观众可能已经发现了,哎呀,玩意顺序表里没有元素,你再删除那不就出错了吗?是的,所以我们还需要改进一下代码。

void SLPopBack(SL* psl)
{
    if(psl->size==0)
    {
        return;
    }

   psl->size--;
}



void SLPopFront(SL* psl)
{
    if(psl->size==0)
    {
        return;
    }
    int i =0;
    while(i<psl->capcity-1)
    {
        psl->a[i] = psl->a[i+1];        
        i++;
    }
   psl->size--;
}

这里呢,我们采用了一种温柔的方法进行检查,当然,我们也可以暴力一点直接使用assert来进行检查。在之后的代码中我会开始采用assert来检查。

好的,那么接下来呢,我们来写一个从任意位置插入的函数

原理与头插类似,我们直接来看代码

void SLInsert(SL* psl,int pos,SLDateType x)
{
    assert(pos>=0&&pos<=psl->size);
    SLCheckCapcity(psl);
    int i =pos;
    while(i<psl->capcity-1)
    {
        psl->a[i] = psl->a[i+1];        
        i++;
    }
    psl->a[pos] = x;
    psl->size++;

}

这里断言的目的是为了防止pos的位置越界,因为assert内部的东西一旦为假他就报错了。

当然,有在某个位置插入数据,就应该有在某个位置删除数据。他的原理还是与头删类似

void SLEanse(SL* psl,int pos,SLDateType x)
{
    assert(pos>=0&&pos<psl->size)
    int i =pos;
    while(i<psl->capcity-1)
    {
        psl->a[i] = psl->a[i+1];        
        i++;
    }
   psl->size--;
}

值得注意的是,上段代码的断言中,已经包括了size=0的情况了,所以不需要在进行额外的判断。

之后,我们再来搞一个查找,因为我们现在学习的算法较少,并且排序的代价又很大,所以我们直接采取最简单的遍历来实行

int SLFind(SL* psl,SLDateType x)
{
    for(int i=0;i<psl->size;i++)
    {
         if(psl->a[i]==x)
         {
            return i;
         }   
    }
    return -1;
}

然后呢,我们只需要再写一个打印函数就可以了

void SLPrint(SL* psl)
{
    assert(psl);
    for(int i=0;i<psl->size;i++)
    {
        printf("%d ",psl->a[i]);
    }
    printf("\n");
}

然后就可以自己测试一下了,好了,关于顺序表的内容就到这里。我们下次再见。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值