顺序表及相关基本操作

顺序表是在计算机内存中以数组的形式保存的线性表,是用一段物理地址连续的的存储单元依次存储数据元素的线性结构。

静态顺序表容量是定好的,很多操作会受限,这里仅展示动态顺序表

typedef int SLDataType;
typedef struct SeqList
{
    SLDataType* a;//指向动态开辟的数组
    int size;//记录存储了多少个有效数据
    int capicity;//空间容量大小
}SL;

下面是顺序表的几个基本操作

初始化:

void SLInit(SL* ps)
{
    assert(ps);
    ps->a=NULL;
    ps->size=0;
    ps->capacity=0;
}
    

销毁:

void SLDestroy(SL* ps)
{
    assert(ps);
    if(ps->a)
{
    free(ps->a);
    ps->a=NULL;
    ps->size=ps->capicity=0;
}
}

打印:

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

尾插(在顺序表末尾插入一个数):

void SLPushBack(SL* ps,SLDataType x)
{
    assert(ps);
    //扩容
    if(ps->size==ps->capicity)
 {
    int newCapacity=ps->capacity==0?10:ps->capacity *2;
    SLDataType* tmp=(SLDataType*)realloc(ps->a,newCapacity*sizeof(SLDatatype));
    if(tmp==NULL)
   {
      perror("realloc fail");
      exit(-1);
   }
    ps->a=tmp;
    pc->capacity=newCapacity;
 }
    ps->a[ps->size]=x;
    ps->size++;
 
}

      当size和Capacity值相等时,表已经满了,表尾没有地方可供我们插入数据了,考虑给表扩容,扩容这里用了一个三目运算符,判断表容量是否为零,不是,就在原容量上扩大二倍,如果原容量为零,表示这是一个刚初始化的表,0乘2还是0,为了避免这种情况,就暂时给它一个为10的容量值(这里的10也可以是别的数)。

       使用realloc扩容时,注意realloc的返回类型是void*,这里就需要强制类型转换一下,把返回值类型转换成SLDataType*。realloc的作用是在指针a的位置开始,进行扩容,括号里的第二个参数newCapacity*sizeof(SLDataType)不是在原来的基础上再扩大的量,而是扩大后新容量是多少这里就写多少,申请成功后返回调整之后的内存块地址。申请失败会返回NULL,为防止失败后将一个空指针赋给a,我们可以先用一个指针tmp接收这个内存块的地址,这个tmp的作用就是判断realloc是否申请成功,tmp为空,perror报错,退出,tmp不为空,再将tmp赋给a。

       原有数据是size个,从0到size-1,所以把需要插入的数据x放在size的位置上就好了,因为增加了一个,最后再给size加一。

尾删(删除顺序表尾部数据):

void SLPopBack(SL* ps)
{
    assert(ps);
    assert(ps->size>0);//检查一下表是否为空,不为空,程序继续执行,否则编译器报错
    ps->size--;
}

     用assert检查一下表是否为空,不为空,程序继续执行,否则编译器报错

头插(在顺序表头部插入一个数据):

 

void SLCheckCapacity(SL*ps)
{
    assert(ps);
    //扩容
    if(ps->size==ps->capicity)
 {
    int newCapacity=ps->capacity==0?10:ps->capacity *2;
    SLDataType* tmp=(SLDataType*)realloc(ps->a,newCapacity*sizeof(SLDatatype));
    if(tmp==NULL)
   {
      perror("realloc fail");
      exit(-1);
   }
    ps->a=tmp;
    pc->capacity=newCapacity;
 }
}
void SLCheckCapacity(SL*ps);

void SLPushFront(SL* ps,SLDataType x)
{
    //检查容量
    assert(ps);
    SLCheckCapacity(ps);
    //挪动数据
    int end=ps->size-1;
    while(end>=0)
{
    ps->a[size+1]=ps->a[size];
    --end;
}
    p->a[0]=x;
    ps->size++;
}
    

        在进行头插操作之前,先检查一下现有容量够不够我们再插入一个数据,这里就调用一个函数SLCheckCapacity(这个函数的具体解析在上一部分尾插中涉及,在上一部分是直接写进尾插函数中的,也可以把扩容单另写成函数SLCheckCapacity,这样就可以在尾插头插第一步检查容量时直接调用)。

        挪动数据时,从后往前依次挪动。

头删(删除顺序表中第一个数据):

        与头插相反,头删挪动数据时,从前往后依次挪动 。

void SLPopFront(SL*ps)
{
    assert(ps);
    assert(ps->size>0);
    int begin=1;
    while(begin<ps->size)
{
    ps->a[begin-1]=ps->a[begin];
    ++begin;
}
    ps->size--;
}

        同样需要使用assert检查一下,表为空时,编译器会报错,否则继续进行下面的头删步骤。

在pos位置插入数据:

void SLInsert(SL*ps,int pos,SLDataType x)
{
    assert(ps);
    assert(pos>=0);
    assert(pos<=ps->size);
    SLCheckCapacity(SL*ps);
    int end=ps->size-1;
    while(end>=pos)
{
    ps->a[end+1]=ps->a[end];
    end--;
}
    ps->a[pos]=x;
    ps->size++;
}

        用assert检查一下pos位置是否合法 。   

        当pos等于0时,相当于头插;当pos等于size时,相当于尾插,也就是说,该函数就可以替换上面的头插尾插函数了。

在pos位置删除数据:

void SLErase(SL*ps,int pos)
{
    assert(ps);
    assert(pos>=0);
    assert(pos<ps->size);
    int begin=pos+1;
    while(begin<ps->size)
{
    ps->a[begin-1]=ps->a[begin];
    begin++;
}
    ps->size--;
}
    

      同理于SLInsert。

查找(查找数x在顺序表中的哪个位置):

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

        在表中找到了x,返回位置,找不到,返回-1。

P.S:代码中仅展示相关功能实现的语句,没有包含头文件,实际操作时一定不要忘记#include<stdio.h>#include<stdilb.h>#include< assert.h>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值