关于顺序表的基本操作(c语言)

一.简介:

顺序表是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;
}

作者也是考研生,会陆续更新接下来数据结构的代码内容,希望能给广大考研生提供帮助,如有错误,欢迎指出,一起进步!纯手打干货,写文章不易,喜欢的点赞,觉得有用的收藏,点个关注,大家的点赞、收藏、关注便是作者持续更新分享的动力!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值