一.简介:
顺序表是C语言中的一种数据结构,它通常基于数组实现。顺序表允许我们在连续内存区域上保存线性数据,并且支持快速的随机访问。
通常情况下,顺序表具有以下特点:
*长度固定:一旦创建,其长度就不可以改变。
*支持随机访问:我们可以使用下标(索引)获取指定位置的元素。
*适合静态数据存储:对于只需要在运行时读取而无需修改的数据集合,如静态配置信息等,使用 顺序表非常方便和高效。
由于顺序表在内部实现上通常是一个数组,在进行插入、删除等操作时可能需要进行大量的数据移动,因此,对于需要频繁地增删数据的情况,顺序表性能会受到影响。此时,链表可能更适合用来存储和操作动态数据。后续会再跟新链表的基本操作。
二.顺序表的定义与基本操作
值得注意的是,由于我们使用的是c语言,所以预处理需要做一些处理,比如我们需要以下头文件
代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
其中有了#include<stdlib.h>,我们才可以malloc和free
有了#include<stdbool.h>,我们才可以使用bool
我将介绍一下顺序表的结构体定义,顺序表的静态存储与动态存储,并基于动态存储解释顺序表的基本操作。以下是我将介绍的基本操作的函数声明,结尾我会放入完整代码。(过程如有错误,请指出,虚心学习,学无止境!)
代码如下:
void InitList(SeqList* L);
void DestroyList(SeqList* L);
int GetElem(SeqList L,int i);
int LocateElem(SeqList L,int e);
bool ListInsert(SeqList* L,int i,int e);
bool ListDelete(SeqList* L,int i,int* e);
void IncreaseSize(SeqList* L,int len);
bool Empty(SeqList L);
void PrintList(SeqList);
int Length(SeqList L);
1.实现顺序表的结构体定义:
顺序表的静态存储结构体定义:
代码如下:
#define Maxsize 10
typedef struct {
int data[Maxsize];
int length;
} SqList;
SqList L;
以上为顺序表的静态存储,通常我们更倾向于使用顺序表的动态存储,因为动态存储在顺序表的容量不够时可以增加容量,而静态存储在定义的那一刻就已经固定了容量,无法再更改。
顺序表的动态存储结构体定义:
代码如下:
typedef struct
{
int* data;
int length;
int maxsize;
}SeqList;
由于动态存储更广泛使用,所以接下来的基本操作基于顺序表的动态存储来进行解释说明。
2.初始化
代码如下:
void InitList(SeqList* L)
{
L->data=(int*)malloc(sizeof(int)*Maxsize);
L->length=0;
L->maxsize=Maxsize;
}
3.销毁
代码如下:
void DestroyList(SeqList* L)
{
free(L->data);
L->data=NULL;
L->length=0;
L->maxsize=0;
}
4.查找
查找分为两种,一种是通过给定的位序得到顺序表中该位置的数据,一种是通过给定的数据得到顺序表中该数据的位置,注意不要混淆。此外,读者还要明白位序和顺序表中下标的区别,位序是从1开始算起,而顺序表中的下标是从0开始算起,要分辨清楚哦。
第一种:通过给定位序查找表中元素
代码如下:
int GetElem(SeqList L,int i)
{
if(i<1||i>L.length)
return 0;
return L.data[i-1];
}
给定的位序如果是小于1或者大于表长,那便是无效数据,返回0;
反之,则返回表中数据,注意返回的是i-1,理由开头解释过了。
同时,为什么这个函数我们是用的int类型而不是bool类型呢?因为我们要返回的数据类型是int
我们开始的定义中,Elemtype(定义的数据类型)为int,为了返回数据,我们的函数定义为int,如果没有返回数据,也即失败了,我们便返回0,返回0的意思便是返回失败。
第二种:通过给定值查找表中等于该值的数据的位置
代码如下:
int LocateElem(SeqList L,int e)
{
for(int i=0;i<L.length;i++)
{
if(L.data[i]==e)
return i+1;
}
return 0;
}
我们通过遍历,直到遍历到元素中的数据的值为给定的数据值,直接返回i+1,也即该元素在表中的下标+1,返回的是位序,否则的话没有相应元素,我们返回0代表返回失败。
同时我们要注意,在for循环里定义i这个操作是c99才可以使用的操作,如果是非c99,我们在外面定义int i,再把i放到for循环里令i=0即可。
5.插入
插入操作我们不但要注意位序和下标的区别,
同时还要留意:插入的时候,是从表尾开始各个元素往后移动一位;删除的时候,是从删除位置开始各个元素往前移动一位。这是一个小细节。
代码如下:
bool ListInsert(SeqList* L,int i,int e)
{
if(i<1||i<L->length+1)
return false;
if(L->length>=L->maxsize)
return false;
for(int j=L->length;j>=i;j--)
L->data[j]=L->data[j-1];
L->data[i-1]=e;
L->length++;
return true;
}
如果给定的位序小于零或者大于表长+1,则返回false。
这里为什么是表长+1呢?是因为我们在进行插入操作的时候,插入之后的位置我们都是要往后移动的,表尾一样要往后移动一位,此时表长+1。
同时,如果此时表长超过了表的最大容量的话,我们没有多余容量再进行插入操作,此时的情况也是false。如果上述的情况都不是的话,则我们可以进行遍历来将表中的元素从表尾开始往后移动一位,具体操作便是将前一个元素赋值给后一个元素。
接着便是插入位置赋值e,表长+1,返回true。
6.删除
代码如下:
bool ListDelete(SeqList* L,int i,int* e)
{
if(i<1||i>L->length)
return false;
*e=L->data[i-1];
for(int j=i;j<L->length;j++)
L->data[j-1]=L->data[j];
L->length--;
return true;
}
这里无需length+1,要注意的是e是返回删除的元素值,所以这里的e是传入的int*类型
7.扩容
代码如下:
void IncreaseSize(SeqList* L,int len)
{
int* p=L->data;
L->data=(int*)malloc(sizeof(int)*(len+L->maxsize));
for(int i=0;i<L->length;i++)
L->data[i]=p[i];
L->maxsize+=len;
free(p);
}
通过定义指针p指向L->data,旨在保存原有的数据。
然后对L->data重新动态分配得到扩容后的内存空间。
接着通过遍历赋值原有的数据并修改表的最大容量。
最后注意要释放指针p的内存空间。
8.判空
代码如下:
bool Empty(SeqList L)
{
return (L.length==0);
}
代码效果等同于:
bool Empty(SeqList L)
{
if (L.length==0)
return true;
else
return false;
}
9.遍历输出
代码如下:
void PrintList(SeqList L)
{
for(int i=0;i<L.length;i++)
printf("L.data[%d]=%d\n",i,L.data[i]);
}
10.返回表长
代码如下:
int Length(SeqList L)
{
return L.length;
}
三.完整代码
代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#define Maxsize 10
typedef struct
{
int* data;
int length;
int maxsize;
}SeqList;
void InitList(SeqList* L);
void DestroyList(SeqList* L);
int GetElem(SeqList L,int i);
int LocateElem(SeqList L,int e);
bool ListInsert(SeqList* L,int i,int e);
bool ListDelete(SeqList* L,int i,int* e);
void IncreaseSize(SeqList* L,int len);
bool Empty(SeqList L);
void PrintList(SeqList);
int Length(SeqList L);
int main()
{
return 0;
}
void InitList(SeqList* L)
{
L->data=(int*)malloc(sizeof(int)*Maxsize);
L->length=0;
L->maxsize=Maxsize;
}
void DestroyList(SeqList* L)
{
free(L->data);
L->data=NULL;
L->length=0;
L->maxsize=0;
}
int GetElem(SeqList L,int i)
{
if(i<1||i>L.length)
return 0;
return L.data[i-1];
}
int LocateElem(SeqList L,int e)
{
for(int i=0;i<L.length;i++)
{
if(L.data[i]==e)
return i+1;
}
return 0;
}
bool ListInsert(SeqList* L,int i,int e)
{
if(i<1||i<L->length+1)
return false;
if(L->length>=L->maxsize)
return false;
for(int j=L->length;j>=i;j--)
L->data[j]=L->data[j-1];
L->data[i-1]=e;
L->length++;
return true;
}
bool ListDelete(SeqList* L,int i,int* e)
{
if(i<1||i>L->length)
return false;
*e=L->data[i-1];
for(int j=i;j<L->length;j++)
L->data[j-1]=L->data[j];
L->length--;
return true;
}
void IncreaseSize(SeqList* L,int len)
{
int* p=L->data;
L->data=(int*)malloc(sizeof(int)*(len+L->maxsize));
for(int i=0;i<L->length;i++)
L->data[i]=p[i];
L->maxsize+=len;
free(p);
}
bool Empty(SeqList L)
{
return (L.length==0);
}
void PrintList(SeqList L)
{
for(int i=0;i<L.length;i++)
printf("L.data[%d]=%d\n",i,L.data[i]);
}
int Length(SeqList L)
{
return L.length;
}
作者也是考研生,会陆续更新接下来数据结构的代码内容,希望能给广大考研生提供帮助,如有错误,欢迎指出,一起进步!纯手打干货,写文章不易,喜欢的点赞,觉得有用的收藏,点个关注,大家的点赞、收藏、关注便是作者持续更新分享的动力!