C语言数据结构——顺序表

本文详细介绍了线性表的概念,重点剖析了顺序表的结构(包括静态和动态)、功能实现(如初始化、销毁、打印等),以及其在插入和删除操作中的时间复杂度和空间效率问题。讨论了顺序表在实际应用中的优缺点,特别是动态扩容带来的空间浪费。
摘要由CSDN通过智能技术生成

1.线性表

 线性表是一种在实际中广泛使 用的数据结构,常见的线性表:顺序表、链表、栈、队列....

线性表在 逻辑上是线性结构 ,也就说是连续的一条直线。但是在 物理结构上并不一定是连续 的,
线性表在物理上存储时,通 常以数组和链式结构 的形式存储

2.顺序表

2.1概念及结构

概念

顺序表是用一段 物理地址连续 的存储单元依次存储数据元素的线性结构,一般情况下采用数组存
储。在数组上完成数据的增删查改。
顺序表一般可以分为:
1. 静态顺序表:使用定长数组存储元素
2. 动态顺序表:使用动态开辟的数组存储。

2.2 基础功能的实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致 N 定大了,空
间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间
大小,所以下面我们实现动态顺序表。
// 顺序表的初始化
void SLInit(SL* psl)
{
	assert(psl);


	psl->a = NULL;
	psl->size = 0;
	psl->capacity = 0;
}


//顺序表的销毁
void SLDestroy(SL* psl)
{
	assert(psl);


	if (psl->a != NULL)
	{
		free(psl->a);
		psl->a = NULL;
		psl->size = 0;
		psl->capacity = 0;
	}
}


//顺序表的打印
void SLPrint(SL* psl)
{
	assert(psl);


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


//检查顺序表是否满容,满了则扩容
void SLCheckCapacity(SL* psl)
{
	assert(psl);


	if (psl->size == psl->capacity)
	{
        //解决设计时顺序表为容量为0时无法扩容的问题!!
		int newCapacity = psl->capacity == 0 ? 4 : psl->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(psl->a, sizeof(SLDataType) * newCapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}


		psl->a = tmp;
		psl->capacity = newCapacity;
	}
}


//顺序表尾插
void SLPushBack(SL* psl, SLDataType x)
{
	assert(psl);
	SLCheckCapacity(psl);    //检查顺序表是否为满


	psl->a[psl->size] = x;
	psl->size++;
}


//顺序表头插
void SLpushFrot(SL* ps1, SLDataType x)
{
	SLCheckCapacity(ps1);    //检查顺序表是否为满
	int end = (ps1->size) ;

    //从后面前移动数据
	for (; end >0; end--)
	{
		ps1->a[end] = ps1->a[end-1];
	}

	*(ps1->a) = x;
	(ps1->size)++;
}




//顺序表头删
void SLPopFrot(SL* ps1)
{
	SLCheckCapacity(ps1);    //检查顺序表是否为满
	int i = 0;
	int* end = ps1->a;

	for (i = 0; i < (ps1->size)-1; i++)
	{
		end[i] = end[i+1];
	}

    //如果还有有效数据则删除一个,没有则不删
    if(psl->size)
	    ps1->size--;
    //打印提示错误信息
	if (ps1->size < 0)
		perror("SLPopFrot not data!");
}


//顺序表尾删
void SLPopBack(SL* ps1)
{
	if (ps1->size <= 0)
		perror("SLPopFrot not data!");
	(ps1->size)--;
}


// 顺序表查找
int SeqListFind(SL* ps1, SLDataType x)
{
	for (int i = 0; i < ps1->size; i++)
	{
		if ((ps1->a)[i] == x)
		{
			return i+1;
		}
	}
	return EOF;
}


// 顺序表在pos位置插入x
void SeqListInsert(SL* ps1, int pos, SLDataType x)
{
	SLCheckCapacity(ps1);
	int* end = (ps1->a) + (ps1->size) - 1;
	while (end >= (ps1->a) + pos - 1)
	{
		*(end + 1) = *end;
		end--;
	}
	ps1->a[pos-1] = x;
	ps1->size++;
}


// 顺序表删除pos位置的值
void SeqListErase(SL* ps1, int pos)
{
	int i = 0;
	int* end = (ps1->a) + pos - 1;
	for (i = 0; i < (ps1->size) - pos + 1; i++)
	{
		end[i ] = end[i+1];
	}
	ps1->size--;
}

3.思考

1. 中间 / 头部的插入删除,时间复杂度为 O(N)
2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
3. 增容一般是呈 2 倍的增长,势必会有一定的空间浪费。例如当前容量为 100 ,满了以后增容到
200 ,我们再继续插入了 5 个数据,后面没有数据插入了,那么就浪费了 95 个数据空间。
  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值