基于C语言的顺序表实现

->Gitee源代码点击这里<-
顺序表的本质是一个动态开辟的数组
实现数据表,首先需要创建一个结构体,该结构体的成员记录了该数组的信息
以整形顺序表为例,为了方便以后代码的修改和维护,我们将int重命名

typedef int SLDatatype;

typedef struct SeqList
{
	SLDatatype* a;   //指向数组的指针
	int size;		//数组有效数据的长度
	int capacity;	//数组的最大容量
}SeqList;

我们创建一个结构体变量

struct SeqList myseq;

此时,变量下的成员都需要随机值,因此我们需要一个初始化成员变量的接口(即函数)
由于成员的值需要发生改变,所以我们需要传地调用函数
初始化时,我们假设需要给定一个初始的数组大小

void SeqListInit(SeqList* pq); //接口的声明
void SeqListInit(SeqList* pq)
{
	assert(pq);    //防止传给函数的地址为NULL
	pq->a = (SLDatatype*)malloc(sizeof(SLDatatype) * 4); //初始大小为4个整形空间
	if (pq->a == NULL)
	{
		printf("Init Failed\n");
		exit(-1);
	}

	pq->capacity = 4;    //数组的初始最大容量为4
	pq->size = 0;		//初始化时数组内还没有有效数据
}

由于数组的动态开辟的,所以使用完之后需要将空间释放,因此对应的,需要有一个释放动态开辟空间的接口

void SeqListDestroy(SeqList* pq);
void SeqListDestroy(SeqList* pq)
{
	assert(pq);
	free(pq->a);
	pq->a = NULL;
	pq->size = pq->capacity = 0;
}

数组的准备工作已经完成,有了数组,就需要完成数据的处理部分,即数据的增删改查
一、插入数据的接口
①实现任意位置插入
我们需要接口实现能在数组的任意位置 _pos _处插入数据(注意:顺序表的数据必须是连续的,所以任意位置是有限制的,即0<pos<size)
插入数据的原理:从数组的最后一个数据开始,依次往后挪动一个空间,到pos处停止,将pos处原本的数据覆盖成想要插入的数据
而在插入数据之前,我们需要判断数组的容量是否已经满,如果数组满了,再往数组里插入数据显然是不合逻辑的,因此需要对数组进行扩容
所以为了完成插入数据的接口,我们还需要准备一个检查容量判断是否扩容的接口

void CheckCapacity(SeqList* pq);
void CheckCapacity(SeqList* pq)
{
	if (pq->size == pq->capacity) //数组的有效数据个数达到容量大小时则表示数组已满
	{
        //满了则需要对数组扩容
		SLDatatype newa = (SLDatatype*)realloc(pq->a, sizeof(SLDatatype) * 2 * pq->capacity);
		if (newa == NULL)
		{
			printf("Realloc Failed\n");
			exit(-1);
		}
		pq->a = newa;
		pq->capacity *= 2;
	}
}

接下来完成数据插入接口,接口的参数需要结构体变量的地址,插入数据的位置以及插入数据的值

void SeqListPush(SeqList* pq, int pos, SLDatatype data);
void SeqListPush(SeqList* pq, int pos, SLDatatype data)
{
	assert(pq);
	assert(pos >= 0 && pos <= pq->size);
	CheckCapacity(pq);
	int end = 0;
	for (end = pq->size - 1; end >= pos; end--)
	{
		pq->a[end + 1] = pq->a[end];
	}
	pq->a[pos] = data;
	pq->size++;
}

此时可以对改接口进行测试了(测试过程略),为了方便测试,我们可以增加一个打印数组数据的接口以便于我们观察数组中的值

void SeqPrint(SeqList* pq);
void SeqPrint(SeqList* pq)
{
	for (int i = 0; i < pq->size; i++)
	{
		printf("%d ", pq->a[i]);
	}
	printf("\n");
}

②有了上面的任意位置插入的接口,我们可以通过该接口的复用来实现更简便的头插数据和尾插数据接口
头插数据:

void SeqListPushFront(SeqList* pq, SLDatatype data);
void SeqListPushFront(SeqList* pq, SLDatatype data)
{
	SeqListPush(pq, 0, data);
}

尾插数据:

void SeqListPushBack(SeqList* pq, SLDatatype data);
void SeqListPushBack(SeqList* pq, SLDatatype data)
{
	SeqListPush(pq, pq->size, data);
}

二、数据的删除
删除 pos 处数据的原理为:pos 后面的数据整体往前挪动一个空间,以覆盖掉pos处的值
完成删除接口时,我们需要考虑空数组的情况,因此我们需要先添加一个判空接口

bool SeqListIsEmpty(SeqList* pq);
bool SeqListIsEmpty(SeqList* pq)
{
	assert(pq);
	return pq->size == 0;  //如果数组为空,返回true,表示数组确实为空
}

完成删除接口

void SeqListPop(SeqList* pq, int pos);
void SeqListPop(SeqList* pq, int pos)
{
	assert(pq);
	assert(!SeqListIsEmpty(pq));
	int begin = 0;
	for (begin = pos; begin < pq->size-1; begin++)
	{
		pq->a[begin] = pq->a[begin + 1];
	}
	pq->size--;
}

和数据插入同理,可通过函数复用实现头删和尾删接口

//头删
void SeqListPopFront(SeqList* pq);
//尾删
void SeqListPopBack(SeqList* pq);

void SeqListPopFront(SeqList* pq)
{
	SeqListPop(pq, 0);
}

void SeqListPopBack(SeqList* pq)
{
	SeqListPop(pq, pq->size-1);
}

三、数据的修改

void SeqListModify(SeqList* pq,int pos,SLDatatype data);
void SeqListModify(SeqList* pq, int pos, SLDatatype data)
{
	assert(pq);
	assert(pos >= 0 && pos <= pq->size);
	pq->a[pos] = data;	
}

四、数据的查找

int SeqListSearch(SeqList* pq, SLDatatype data);
int SeqListSearch(SeqList* pq, SLDatatype data)
{
	assert(pq);
	for (int i = 0; i < pq->size; i++)
	{
		if (pq->a[i] == data)
		{
			return i;   //查找到则返回下标
		}
	} 
	return -1;   //为查找到则返回-1
}

至此顺序表的实现已经完成

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值