数据结构线性表之顺序表

线性表(linear list)

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结
构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储

重点:区分逻辑结构和物理结构

拿线性表来说,逻辑上应该是连续的,一个接一个的。

然而在物理上(计算机存储结构中),线性表的底层实现有很多方式,比如可以选择顺序结构(存储单元的地址是连续的),也可以选择链式结构(存储单元的地址不一定连续)

顺序表

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组 上完成数据的增删查改

//动态顺序表---基本接口
typedef struct SeqList
{
	int* a;
	size_t size;//存储数据大小
	int capacity;//存储空间大小
}SeqList;
void SeqListCheckCapacity(SeqList* psl);//检查扩容
void SeqListshow(SeqList* psl);//打印数据
void SeqListInit(SeqList* psl);//初始化顺序表
void SeqListDestory(SeqList* psl);//销毁顺序表

//时间复杂度是O(1)
void SeqListPushBack(SeqList *psl,int x);//尾插---向末尾插一个元素
void SeqListPopBack(SeqList* psl);//尾删---向末尾删一个元素

//时间复杂度是O(n)
void SeqListPushFront(SeqList* psl,int x);//头插---向头插一个元素,其他元素向后挪动
void SeqListPopFront(SeqList* psl);//头删---向头删一个元素,其他元素向前挪动

void SeqListInsert(SeqList* psl, size_t pos, int x);//任意位置插入,后面元素向后挪动
void SeqListErase(SeqList* psl, size_t pos);//删除pos位置的元素,后面元素向前挪动
int SeqListFind(SeqList* psl, int x);//查找数据
void SeqListModify(SeqList* psl,size_t pos,int x);//修改元素(替换元素)

任意位置插入基本思路,其他插入等同理

void SeqListInsert(SeqList* psl, size_t pos, int x)//下标位置插入
{
	1.pos本意不能为负数,因此写size_t

	//暴力检查
	assert(psl);//空指针
	assert(pos <= psl->size);//超出范围

	SeqListCheckCapacity(psl);//检查增容---否则释放得时候检查越界会出现问题
	//温和检查
	/*if (pos > psl->size)
	{
		printf("越界了");
		return;
	}*/

	//size_t end = psl->size - 1;//这里不能-1
	2.如果这里end改为int,其他类型都要改,否则下面判断的时候end>=pos ,end有符号整形要转换为无符号整形会很大,会出现-1大于0的情况(整型提升)
	//for (end;end >= pos;end--)
	//{
	//	psl->a[end + 1] = psl->a[end];
	//}
	//psl->a[pos] = x;
	//psl->size++;

	//优化代码 
	size_t end = psl->size;
	while (end > pos)//在pos后一个位置停下
	{
		psl->a[end] = psl->a[end - 1];
		--end;
	}
	psl->a[pos] = x;
	psl->size++;
}

基本接口的实现
void SeqListshow(SeqList* psl)
{
	assert(psl);
	size_t i = 0;
	for (i = 0;i < psl->size;i++)
	{
		printf("%d ", psl->a[i]);
	}
	printf("\n");
}

void SeqListInit(SeqList* psl)
{
	assert(psl);
	psl->a=NULL;
	psl->capacity = 0;
	psl->size = 0;
}
void SeqListDestory(SeqList* psl)//销毁顺序表
{
	assert(psl);
	free(psl->a);
	psl->a = NULL;
	psl->capacity = psl->size = 0;
}
void SeqListPushBack(SeqList* psl, int x)//尾插---向末尾插一个元素
{
	assert(psl);

	SeqListCheckCapacity(psl);
	psl->a[psl->size] = x;//注意psl->a是一个数组,我们需要找到下标元素
	psl->size++;

	//复用Insert版本(有个问题)
	/*如果插入0位置,end算出来是-1,变成无符号后结果非常大*/
	//SeqListInsert(psl, psl->size, x);
}
void SeqListPopBack(SeqList* psl)//尾删
{
	//是否会变成负的?---越界是一种抽查,可能报错,可能不会报错
	assert(psl);
	if (psl->size > 0)
	{
		psl->size--;//将空间缩短
	}
}
void SeqListCheckCapacity(SeqList* psl)//检查扩容
{
	assert(psl);
	if (psl->capacity == psl->size)//满了则扩容
	{
		//判断容器量为0?为4:变成原来的两倍
		size_t InitCapacity = psl->capacity == 0 ? 4 : (psl->capacity) * 2;
		int* tmp = realloc(psl->a, sizeof(int) * InitCapacity);//如果是空,相当与malloc
		//申请失败
		if (tmp == NULL)
		{
			printf("扩容失败:%s\n", strerror(errno));
			exit(-1);//直接结束程序
		}
		//申请正常
		else
		{
			psl->a = tmp;
			psl->capacity = InitCapacity;
			printf("扩容成功\n");
		}
	}
}
//头插---向头插一个元素
void SeqListPushFront(SeqList* psl, int x)
{
	//检查扩容
	assert(psl);
	SeqListCheckCapacity(psl);
	//向后平移
	int end = psl->size - 1;
	for (end;end >= 0;end--)
	{
		psl->a[end + 1] = psl->a[end];
	}
	psl->a[0] = x;
	psl->size++;//因为添加了一个元素,所以要++
}
//头删---向头删一个元素
void SeqListPopFront(SeqList* psl)
{
	assert(psl);
	//删除其实就是覆盖
	size_t first = 0;
	for (first;first < psl->size-1;first++)
	{
		//最后一个不要first+1了
		psl->a[first] = psl->a[first+1];
	}
	if (psl->size>0)//当psl->size==0时不能再减了
	{
		psl->size--;//防止size变成负值了
	}
	//不用就得还,不然内存泄露
}

void SeqListInsert(SeqList* psl, size_t pos, int x)//下标位置插入
{
	//pos不能为负数,因此写size_t
	//暴力检查
	assert(psl);//空指针
	assert(pos <= psl->size);//超出范围
	SeqListCheckCapacity(psl);//检查增容---否则释放得时候检查越界会出现问题
	//温和检查
	/*if (pos > psl->size)
	{
		printf("越界了");
		return;
	}*/
	//极端思维
	//if (pos == 0)
	//{
	//	SeqListPushFront(psl,x);
	//	return;
	//}
	//size_t end = psl->size - 1;//这里不能-1
	////如果这里end改为int,其他类型都要改,否则下面判断的时候end>=pos ,end有符号整形要转换为无符号整形会很大,会出现-1大于0的情况(整型提升)
	//for (end;end >= pos;end--)
	//{
	//	psl->a[end + 1] = psl->a[end];
	//}
	//psl->a[pos] = x;
	//psl->size++;

	//优化代码
	size_t end = psl->size;
	while (end > pos)
	{
		psl->a[end] = psl->a[end - 1];
		--end;
	}
	psl->a[pos] = x;
	psl->size++;
}

void SeqListErase(SeqList* psl, size_t pos)//删除pos位置数据
{
	assert(psl);
	assert(pos < psl->size);//pos是指的下标,psl->size是个数,永远比它小一个
	SeqListCheckCapacity(psl);//检查增容
	for (pos;pos < psl->size-1;pos++)
	{
		psl->a[pos] = psl->a[pos + 1];
	}
	if (psl->size > 0)//当psl->size==0时不能再减了
	{
		psl->size--;//防止size变成负值了
	}
}
int SeqListFind(SeqList* psl, int x)//查找数据
{
	assert(psl);
	for (size_t i = 0;i < psl->size;i++)
	{
		if (psl->a[i] == x)
		{
			return i;
		}
		
	}
	printf("未找到要查找的数字\n");
	return -1;
}
void SeqListModify(SeqList* psl, size_t pos, int x)
{
	assert(psl);
	assert(pos < psl->size);//psl->size总是大于pos
	psl->a[pos] = x;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值