【C语言数据结构】EP1顺序表

时间:2022-11-02 18:15:33

1.什么是顺序表

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

1.静态顺序表

#define S 100
typedef int Sqlinstdate;
typedef struct Sqlist
{
	Sqlinstdate con[S];
	int sz;
}Sqlist;

静态顺序表中我们使用定长数组来存储数据,所存储的数据不能超过最开始开辟的数组的大小,很多时候并无法满足我们的需求,所以我们更多的使用的是动态开辟的顺序表

2.动态顺序表

typedef int Sqlinstdate;
typedef struct Sqlist
{
	Sqlinstdate* con;
	int sz;
	int capacity;
}Sqlist;

我们使用指针来指向动态开辟的空间,sz记录表中数据的个数,capacity记录表的容量。

这样当表的容量不足时我们可以进一步扩容.

2.实现一个顺序表

对于一个表格我们需要实现他的增删查改,我们可以现在头文件中留好对应功能函数的接口,再在我们的源文件中去实现

#pragma once
#include <assert.h>
#include <stdlib.h>
#define InitCapacity 3
typedef int Sqlinstdate;
typedef struct Sqlist
{
	Sqlinstdate* con;
	int sz;
	int capacity;
}Sqlist;
void Sqlistinit(Sqlist* ptr);//表的初始化
void SqlistDestory(Sqlist* ptr);//表的销毁
void SqlistCheack(Sqlist* ptr);//检查是否已满,已满进行增容
void SqlistInsert(Sqlist* ptr,int x,Sqlinstdate z);//插入数据
void SqlistPrint(Sqlist* ptr);//打印表
void SqlistDel(Sqlist* ptr, int z);//删除
void SqlistFind(Sqlist* ptr, Sqlinstdate z);//查找
void SqlistChange(Sqlist* ptr, int x, Sqlinstdate z);//更改

1.初始化,检查,打印,销毁

void Sqlistinit(Sqlist* ptr)
{
	assert(ptr);
	ptr->capacity = InitCapacity;
	ptr->sz = 0;
	ptr->con = malloc(sizeof(Sqlinstdate)*(ptr->capacity));
}

当我们检查到容量不足时需要进行扩容,扩容时扩容太少频繁进行扩容会导致效率的损耗,而扩容过多又会导致空间的浪费,这里我选择让它每次扩容到原来的二倍

void SqlistCheack(Sqlist* ptr)
{
	assert(ptr);
	if (ptr->capacity == ptr->sz)
	{
		ptr->capacity *= 2;
		Sqlinstdate* pptr = realloc(ptr->con, sizeof(Sqlinstdate) * ptr->capacity);
		assert(pptr);
		ptr->con = pptr;
	}
}
void SqlistDestory(Sqlist* ptr)
{
	assert(ptr);
	free(ptr->con);
	ptr->con = NULL;
}

```c
void SqlistPrint(Sqlist* ptr)
{
	assert(ptr);
	for (int i = 0; i < ptr->sz; i++)
	{
		printf("%d ", ptr->con[i]);
	}
	printf("\n");
}

assert的作用是当条件为假时会中止程序并报错,我用它来检查所传递的指针是否为空,当然你也可以用if()来进行判断

2.插入

注意顺序表中数据必须从头开始连续存放 这里我们大致思考一下表中没有数据,在中间插入,在头部插入,在尾部插入的情况 没有数据时当我们放入数据时只能放到第一位,在中间插入和在头部插入是同一种情况都需要将插入位置开始的数据往后挪动一位

void SqlistInsert(Sqlist* ptr, int x,Sqlinstdate z)//x为插入的位置,z为插入的数据
{
	assert(ptr);
	if (ptr->sz==0)
	{
		ptr->sz++;
		ptr->con[0] = z;
	}
	else if (x >= 0 && x < ptr->sz)
	{
		ptr->sz++;
		for(int i = ptr->sz-1; i>x; i--)
		{
			ptr->con[i] = ptr->con[i - 1];
		}
		ptr->con[x] = z;
	}
	else
	{
		ptr->sz++;
		ptr->con[x] = z;
	}
}

注意当你写完一个程序之后先进行一下测试确定该模块的功能没有问题,我们先在最开写好输出函数的目的也是为了方便测试。 对于我们顺序表需要的头插尾插功能都可以通过调用这个函数来实现。 例如头插函数,我们不做更多演示,以讲解思路为主

SqlistFrontPush(Sqlist* ptr)
{
     assert(ptr);
     SqlistInsert(ptr,ptr->sz);
}

3.删除

void SqlistDel(Sqlist* ptr,int x)
{
	assert(ptr);
	if (x < ptr->sz)
	{
		ptr->sz--;
		for (int i = x; i < ptr->sz; i++)
		{
			ptr->con[i] = ptr->con[i + 1];
		}
	}
}

4. 查询

遍历顺序表即可

void SqlistFind(Sqlist* ptr,Sqlinstdate z)
{
	int sum = 0;
	for (int i = 0; i < ptr->sz; i++)
	{
		if (ptr->con[i] == z)
		{
			sum++;
			printf("下标为%d的位置\n", i);
		}
	}
	if (sum == 0)
		printf("未找到");
}

5.改

修改对应位置的数据即可

void SqlistChange(Sqlist* ptr, int x, Sqlinstdate z)
{
	assert(ptr);
	if (x >= 0 && x < ptr->sz)
	{
		ptr->con[x] = z;
	}
}