C语言顺序表的简单实现

目录

一、数据结构

1.1 数据结构是什么

1.2 为什么需要数据结构

二、顺序表的概念及结构

2.1 线性表

2.2 顺序表分类

2.2.1顺序表和数组的区别

2.2.2顺序表分类

三、动态顺序表的实现

3.1表的初始化

3.2表的销毁

3.3增

3.3.1尾插

3.3.2首插

3.3.3任意位置的插入

四、删

4.1首删

4.2 尾删

4.3任意位置删除

​编辑

五、查

六、通讯录

6.1 增

6.2 查

6.3 删

6.4 改

6.5 实现

七、完整代码


一、数据结构

1.1 数据结构是什么

当我们想要使用⼤量使用同⼀类型的数据时,通过手动定义大量的独立的变量对于程序来说,可读
性非常差,我们可以借助数组这样的数据结构将大量的数据组织在⼀起,结构也可以理解为组织数
据的方式。
数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在⼀种或多种特定关系
的数据元素的集合。数据结构反映数据的内部构成,即数据由那部分构成,以什么方式构成,以
及数据元素之间呈现的结构。

1.2 为什么需要数据结构

程序中如果不对数据进行管理,可能会导致数据丢失、操作数据困难、野指针等情况。
通过数据结构,能够有效将数据组织和管理在⼀起。按照我们的方式任意对数据进行增删改查等操
作。

最基础的数据结构:数组。

1.3 有了数组,为什么还要学习其他的数据结构?

求数组的长度,求数组的有效数据个数,向下标为数据有效个数的位置插入数据(注意:这⾥是
否要判断数组是否满了,满了还能继续插入吗).....
假设数据量非常庞大,频繁的获取数组有效数据个数会影响程序执行效率。
结论:最基础的数据结构能够提供的操作已经不能完全满足复杂算法实现
本文是笔者对顺序表的应用

二、顺序表的概念及结构

2.1 线性表

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

2.2 顺序表分类

2.2.1顺序表和数组的区别

顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口

2.2.2顺序表分类

静态顺序表
struct Seqlist
{
    int arr[100];
    int size;
};//这是静态顺序表,局限性很大,空间给小了不够,给多了浪费

动态顺序表

struct Seqlist
{
	qen* arr;//因为是动态申请,所以这里就不用数组形式,用指针形式
	int size;//有效数据个数
	int space;//申请的空间容量
};//这是动态表,比较灵活

三、动态顺序表的实现

3.1表的初始化

#include"4_13.h"
void testslin()
{
	struct Seqlist s;
		Slin(&s);
}
int main()
{
	testslin();
	return 0;//打断点进行测试
}//测试顺序表初始化与销毁函数

这边调试可以发现并没有出错。

3.2表的销毁

因为动态表涉及到动态内存开辟,所以要记得free

void SlDestory(struct Seqlist* p)
{
	assert(p);
	free(p->arr);
	p->arr = NULL;
}

接下来进行顺序表的增(即在原数据表中插入数据)

3.3增

这里首先来说说首插与尾插

在这之前,我们先将表中存储的数据类型进行重命名为qen(qenre)

typedef int qen;

因为在表中存放数据的时候,不可能只存放一种类型的数据,如果不进行重命名,到存放其他类型

的数据的时候改起来就很麻烦,这里直接使用typedef进行重命名,到时候修改的时候把数据只用

改这里一处就可以了

3.3.1尾插

尾插,即从顺序表的末尾进行数据插入。

定义变量x为想插入的数据

这里由于是直接插入数组的尾部,所以不需要向首插那样考虑数据覆盖的情况。

这里发现,当前顺序表中有效数据个数size正好就是插入数据时的数组下标

那么在成功插入一个数据后,该表中有效数据增加,则需要一个size++

if (p->size == p->space)//判断是否需要扩容p->arr的空间
	{
		p->arr = realloc(p->arr, sizeof(qen) * sizeof(p->arr) * 2);
	}//直接这样写可以吗
	

这样写可能会造成数据丢失

因为realloc函数可能会开辟失败,返回NULL,这样写的话不仅开辟不成功 ,原来放在表中的数

据也丢失了,那就寄了。

那就再搞个指针来接收他,看他是不是NULL,不是NULL再赋值给p->arr

void Slinsertback(struct Seqlist* p, qen num)
{
	assert(p);
	if (p->size == p->space)//判断是否需要扩容p->arr的空间
	{
		//p->arr = realloc(p->arr, sizeof(qen) * sizeof(p->arr) * 2);这样写不行
		//因为realloc函数可能会开辟失败,返回NULL,这样写的话不仅开辟不成功
		//原来的数据也丢失了,那就再搞个指针来接收他,看他是不是NULL,不是NULL再赋值给p->arr
		qen* judge = realloc(p->arr, (sizeof(qen)) * p->space * 2);
        p->space = newspace;//这里记得要把表的总空间进行赋值
		if (judge == NULL)
		{
			perror("");
			return;
		}
		else
			p->arr = judge;
	}
	p->arr[p->size++] = num;//插入在表的末尾,插入成功后表的有效数据+1
}

将扩容操作直接写成个函数

void newspacecheck(struct Seqlist* p)
{
	if (p->size == p->space)//判断是否需要扩容p->arr的空间
	{
		int newspace = p->space == 0 ? sizeof(qen) : 2 * p->space;
        p->space = newspace;//这里记得要把表的总空间进行赋值

		qen* judge = realloc(p->arr, sizeof(qen) * newspace);

		//因为realloc函数可能会开辟失败,返回NULL,这样写的话不仅开辟不成功

		//原来的数据也丢失了,那就再搞个指针来接收他,看他是不是NULL,不是NULL再赋值给p->arr
		if (judge == NULL)
		{
			perror("realloc fali");
			return;
		}
		else
			p->arr = judge;
	}
}

那么我们来测试一下

void testSlinsertback(struct Seqlist* p)
{
	
	Slin(p);
	Slinsertback(p, 1);
	Slinsertback(p, 1);
	Slinsertback(p, 1);
	Slinsertback(p, 1);
	Slinsertback(p, 1);
}

int main()
{
	struct Seqlist s;
	testSlinsertback(&s);
	return 0;//打断点进行测试
}

 

 在这里报了个错误,来看看是什么情况

可以发现这里space是0,所以在这里进行空间开辟的时候,还需要判断原空间是否是0

如果判断是0,重新定义一个变量newspace ,那么这里就默认给newspace开辟qen类型大小的一

个空间,再将代码修改一下

void Slinsertback(struct Seqlist* p,   qen num)
{
	assert
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值