数据结构之手搓顺序表(顺序表的增删查改)

news2024/10/1 10:15:45

目录

文章目录

前言

一、什么是顺序表?

二、动态顺序表的实现

1.头文件定义

2.实现顺序表的初始化

3.检查顺序表空间容量是否足够,不够就增容

4.顺序表的销毁 

5.顺序表的打印 

6.顺序表的尾插 

7.顺序表的头插 

8.顺序表的头删 

9.顺序表的尾删 

10.顺序表的查找 

11.在顺序表指定位置插入数据 

12.顺序表删除指定位置数据

定义汇总代码:

1.   .c文件

2.建议


前言

在我们学习初阶顺序结构的时候,首当其冲学习的就是顺序表,下边我将边讲解边手搓一个顺序表并实现他的增删改查功能


一、什么是顺序表?

概念:顺序表是用⼀段物理地址连续的存储单元依次存储数据元素的线性结构,⼀般情况下采用数组存储。其实顺序表的底层结构就是数组,我们对数组进行封装,实现了增删改查等常用的接口。
顺序表有静态顺序表和动态顺序表。
我们这里主要实现动态顺序表,因为静态顺序表有缺陷,空间给少了不够用,给多了又浪费。

二、动态顺序表的实现

1.头文件定义

代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int DateType;
typedef struct seqlist
{
	DateType* arr;
	int size;//有效的数据个数
	int capacity;//空间容量
}seqlist;

//顺序表的初始化
void SeqListInit(seqlist* ps);
//检查顺序表空间容量是否足够,不够就增容
void SLCheckCapacity(seqlist* ps);
//顺序表的销毁
void SeqListDestroy(seqlist* ps);
//顺序表的打印
void SeqListPrint(seqlist* ps);
//顺序表的尾插
void SeqListPushBack(seqlist* ps, DateType x);
//顺序表的头插
void SeqListPushFront(seqlist* ps, DateType x);
//顺序表的头删
void SeqListPopFront(seqlist* ps);
//顺序表的尾删
void SeqListPopBack(seqlist* ps);

// 顺序表查找
int SeqListFind(seqlist* ps, DateType x);
// 顺序表在pos位置插入x
void SeqListInsert(seqlist* ps, int pos, DateType x);
// 顺序表删除pos位置的值
void SeqListErase(seqlist* ps, int pos);

2.实现顺序表的初始化

代码如下:

//顺序表的初始化
void SeqListInit(seqlist* ps)
{
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

初始化就很简单,就是把指针指向空,有效数据个数和空间容量设为0。因为我们还没有开空间放数据。

3.检查顺序表空间容量是否足够,不够就增容

代码如下:

因为在顺序表的增删查改中要频繁用到这个操作,索性我们就把他封装成一个函数,到时候直接调用会更方便,不用一遍又一遍的去实现。

//检查顺序表空间容量是否足够,不够就增容
void SLCheckCapacity(seqlist* ps)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		DateType* new = (DateType*)realloc(ps->arr, newcapacity * sizeof(DateType));
		if (new == NULL)
		{
			perror("realloc");
			return 1;
		}
		ps->arr = new;
		ps->capacity = newcapacity;
	}
}

这里的思路呢就是先判断如果有效数据个数等于空间容量,那就说明顺序表满了,我们如果要再插入数据的话,就需要扩容,这也是动态顺序表的精髓所在。这里用到了三目操作符和realloc开辟空间。

4.顺序表的销毁 

代码如下:

//顺序表的销毁
void SeqListDestroy(seqlist* ps)
{
	assert(ps);
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

这里的思路也很简单,因为我们要销毁顺序表,free就是释放malloc,realloc,calloc开辟的空间,然后再将ps->arr这个指针设为空,避免它成为野指针,既然空间释放了,那么有效数据个数和空间容量就顺手变成0。

5.顺序表的打印 

代码如下:

//顺序表的打印
void SeqListPrint(seqlist* ps)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d->", ps->arr[i]);
	}
	printf("\n");
}

这个其实没什么好说的,就是简单的循环打印数组中的内容。

6.顺序表的尾插 

代码如下:

//顺序表的尾插
void SeqListPushBack(seqlist* ps, DateType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size] = x;
	ps->size++;
}

前边我们说了size就是有效数据个数,并且顺序表的底层就是数组,比如说顺序表中有1,2,3,4,那就是四个有效数据,而在数组中,他们的下标就是0,1,2,3,那么我们要插入5,我们用size这个数做下标就刚好是在顺序表末尾插入一个数据。然后再让size++,也就是下标++。 

7.顺序表的头插 

代码如下:

//顺序表的头插
void SeqListPushFront(seqlist* ps, DateType x)
{
    assert(ps);
    SLCheckCapacity(ps);
    for (int i = ps->size; i >0; i--)
    {
        ps->arr[i] = ps->arr[i-1];
    }
    ps->arr[0] = x;
    ps->size++;
}

头插比尾插复杂一点点,因为头插需要把顺序表里边的数据整体向后挪一个位置,但是其实就是数组里边的数据整体向后挪一个下标,把0下标让出来插入。 

8.顺序表的头删 

代码如下:

//顺序表的头删
void SeqListPopFront(seqlist* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 1; i < ps->size; i++)
	{
		ps->arr[i-1] = ps->arr[i];
	}
	ps->size-- ;
}

这里其实就是也不算真的删除,就是把0下标之后的数据依次往前挪一位,把0下标的数据覆盖了。

然后size--。

9.顺序表的尾删 

代码如下:

//顺序表的尾删
void SeqListPopBack(seqlist* ps)
{
	assert(ps);
	assert(ps->size);
	ps->size--;
}

尾删就更简单了,就是把有效数据size--,这样就取不到最后一个数据了,等以后写入数据的话直接就把他覆盖了。

10.顺序表的查找 

代码如下:

//顺序表的查找
int SeqListFind(seqlist* ps, DateType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1;
}

简单粗暴,直接for循环再顺序表中找,找到一样的,就返回他的下标,找不到就返回-1;

11.在顺序表指定位置插入数据 

代码如下:

// 顺序表在pos位置插入x
void SeqListInsert(seqlist* ps, int pos, DateType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
    SLCheckCapacity(ps);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}

很简单,pos就是下标,把下标和之后的数据全部向后挪一位,但是在这之前需要判断空间容量是否充足。 

12.顺序表删除指定位置数据

代码如下:

// 顺序表删除pos位置的值
void SeqListErase(seqlist* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	assert(ps->size);
	for (int i = pos; i < ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

这里的思路就是把pos位置之后的值依次往前挪,并且覆盖了pos位置,然后size--。 


定义汇总代码:

1.   .c文件

#include"seqlistt.h"
//顺序表的初始化
void SeqListInit(seqlist* ps)
{
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}
//检查顺序表空间容量是否足够,不够就增容
void SLCheckCapacity(seqlist* ps)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		DateType* new = (DateType*)realloc(ps->arr, newcapacity * sizeof(DateType));
		if (new == NULL)
		{
			perror("realloc");
			return 1;
		}
		ps->arr = new;
		ps->capacity = newcapacity;
	}
}
//顺序表的销毁
void SeqListDestroy(seqlist* ps)
{
	assert(ps);
	if (ps->arr)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}
//顺序表的打印
void SeqListPrint(seqlist* ps)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d->", ps->arr[i]);
	}
	printf("\n");
}
//顺序表的尾插
void SeqListPushBack(seqlist* ps, DateType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	ps->arr[ps->size] = x;
	ps->size++;
}
//顺序表的头插
void SeqListPushFront(seqlist* ps, DateType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	for (int i = ps->size; i >0; i--)
	{
		ps->arr[i] = ps->arr[i-1];
	}
	ps->arr[0] = x;
	ps->size++;
}
//顺序表的头删
void SeqListPopFront(seqlist* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 1; i < ps->size; i++)
	{
		ps->arr[i-1] = ps->arr[i];
	}
	ps->size-- ;
}
//顺序表的尾删
void SeqListPopBack(seqlist* ps)
{
	assert(ps);
	assert(ps->size);
	ps->size--;
}
//顺序表的查找
int SeqListFind(seqlist* ps, DateType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1;
}
// 顺序表在pos位置插入x
void SeqListInsert(seqlist* ps, int pos, DateType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1];
	}
	ps->arr[pos] = x;
	ps->size++;
}
// 顺序表删除pos位置的值
void SeqListErase(seqlist* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	assert(ps->size);
	for (int i = pos; i < ps->size-1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

2.建议

可以将顺序表手搓一边,然后测试一下功能是否完整。如有助益,谓之我幸。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2182096.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LeetCode题练习与总结:二叉树的所有路径--257

一、题目描述 给你一个二叉树的根节点 root &#xff0c;按 任意顺序 &#xff0c;返回所有从根节点到叶子节点的路径。 叶子节点 是指没有子节点的节点。 示例 1&#xff1a; 输入&#xff1a;root [1,2,3,null,5] 输出&#xff1a;["1->2->5","1->…

RabbitMQ基本原理

一、基本结构 所有中间件技术都是基于 TCP/IP 协议基础之上进行构建新的协议规范&#xff0c;RabbitMQ遵循的是AMQP协议&#xff08;Advanced Message Queuing Protocol - 高级消息队列协议&#xff09;。 生产者发送消息流程&#xff1a; 1、生产者和Broker建立TCP连接&#…

国庆同欢,祖国昌盛!肌肉纤维启发,水凝胶如何重构聚合物

在这个国庆佳节&#xff0c;我们共同感受祖国的繁荣昌盛&#xff0c;同时也迎来了知识的探索之旅。今天来了解聚合物架构的重构的研究——《Hydrogel‐Reactive‐Microenvironment Powering Reconfiguration of Polymer Architectures》发表于《Advanced Science》。材料科学不…

【数据结构与算法】算法和算法分析

文章目录 一.算法1.定义2.描述 二.算法与程序三.算法特性四.算法效率的度量4.1算法时间事前分析法算法时间复杂度的渐进表示法分析算法时间复杂度的基本方法 4.2算法空间 数据的逻辑结构映像到内存就是数据的存储结构&#xff0c;针对数据的逻辑结构可以选择多种存储结构。数据…

Kotlin:2.0.0 的新特性

一、概述 kotlin 2.0.0版本英文官方文档 The Kotlin 2.0.0 release is out and the new Kotlin K2 compiler is Stable! Additionally, here are some other highlights: Kotlin 2.0.0发布了&#xff0c;新的Kotlin K2编译器已经稳定了。此外&#xff0c;以下是其他一些亮点: …

Linux操作系统中dubbo

1、简介 dubbo框架是做微服务通信的&#xff0c;是由阿里巴巴开发&#xff0c;后捐赠给阿帕奇基金会。 2、与OpenFeign的区别 dubbo是采用RPC协议实现微服务通信&#xff0c;OpenFeign是采用Http请求的方式实现的。 OpenFeign 最简单的&#xff0c;就是Spring公司开发的&am…

TinyAP:使用TinyML对抗Wi-Fi攻击的智能接入点

论文标题&#xff1a; 英文&#xff1a;TinyAP: An intelligent Access Point to combat Wi-Fi attacks using TinyML中文&#xff1a;TinyAP&#xff1a;使用TinyML对抗Wi-Fi攻击的智能接入点 作者信息&#xff1a; Anand Agrawal 和 Rajib Ranjan Maiti&#xff0c;来自印…

C语言常用标准库 -- 5.<time.h>

目录 引言 5. C标准库--time.h 5.1 简介 5.2 常量与宏 5.3 库变量 5.4 库宏 5.5 库函数 5.6 注意事项 &#x1f308;你好呀&#xff01;我是 程序猿 &#x1f30c; 2024感谢你的陪伴与支持 ~ &#x1f680; 欢迎一起踏上探险之旅&#xff0c;挖掘无限可能&#xff0c;…

线程池面试集

目录 线程池中提交一个任务的流程是怎样的? 线程池有五种状态 如何优雅的停止一个线程? 线程池的核心线程数、最大线程数该如何设置? 如何理解Java并发中的可见性、原子性、有序性? Java死锁如何避免? 线程池中提交一个任务的流程是怎样的? 线程池有五种状态 如何优…

【docker学习】Linux系统离线方式安装docker环境方法

centos7-linux安装docker(离线方式) 下载docker的安装文件 https://download.docker.com/linux/static/stable/x86_64/ 下载的是&#xff1a;docker-18.06.3-ce.tgz 这个压缩文件 将docker-18.06.3-ce.tgz文件上传到centos7-linux系统上&#xff0c;用ftp工具上传即可 解压…

《RabbitMQ篇》基本概念介绍

MQ功能 解耦 MQ允许不同系统或组件之间松散耦合。发送者和接收者不需要直接连接&#xff0c;从而提高了系统的灵活性和可维护性。异步处理 使用MQ可以实现异步消息传递&#xff0c;发送者可以将消息放入队列后立即返回&#xff0c;不必等待接收者处理。这提高了系统的响应速度…

鸿蒙NEXT开发-ArkTS(基于最新api12稳定版)

注意&#xff1a;博主有个鸿蒙专栏&#xff0c;里面从上到下有关于鸿蒙next的教学文档&#xff0c;大家感兴趣可以学习下 如果大家觉得博主文章写的好的话&#xff0c;可以点下关注&#xff0c;博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…

Spring IoC笔记

目录 1.什么是 IoC&#xff1f; 2.IoC类注解&#xff08;五大注解&#xff09; 2.1那为什么要这么多类注解&#xff1f; 2.2五大注解是不是可以混用&#xff1f; 2.3程序被spring管理的条件是&#xff1f; 3.bean对象 3.1Bean 命名约定 3.2获取bean对象 4.⽅法注解 B…

《应急通信产业发展研究报告》蓝皮书解读

近日&#xff0c;中国信通院发布了《应急通信产业发展研究报告》蓝皮书&#xff0c;该报告是对中国应急通信产业现状、发展趋势及其政策环境的综合分析&#xff0c;旨在为行业发展提供参考与指导。以下是小编对该蓝皮书的一些内容解读&#xff1a; 1.应急通信的重要性 应急通信…

2.点位管理|前后端如何交互——帝可得后台管理系统

目录 前言点位管理菜单模块1.需求说明2.库表设计3.生成基础代码0 .使用若依代码生成器最终目标1.创建点位管理2.添加数据字典3.配置代码生成信息4.下载代码并导入项目 4.优化菜单——点位管理1.优化区域管理2.增加点位数3. 合作商4.区域管理中添加查看详情功能5.合作商添加点位…

【拥抱AIGC】通义灵码扩展管理

通义灵码提供了扩展管理&#xff0c;支持自定义指令&#xff0c;满足企业编码场景的扩展诉求。 适用版本 企业标准版、企业专属版 通义灵码管理员、组织内全局管理员&#xff08;专属版&#xff09;在通义灵码控制台-扩展管理中&#xff0c;进行自定义指令的管理、查看自定义…

解锁数据宝藏:AI驱动搜索工具,让非结构化数据“说话

哈哈,说起这个 AI 搜索演示啊,那可真是个有意思的话题!非结构化数据,这家伙虽然难搞,但价值却是杠杠的。今天呢,咱就好好聊聊怎么借助 Fivetran 和 Milvus,快速搭建一个 AI 驱动的搜索工具,让企业能从那些乱七八糟的数据里淘到金子! 一、非结构化数据的挑战与机遇 首…

PCL 点云条件滤波

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 条件定义与滤波 2.1.2 可视化函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&#xff08;长期更新&#…

Python从入门到高手4.1节-掌握条件控制语句

目录 4.1.1 理解条件控制 4.1.2 if, elif, else 4.1.3 条件表达式 4.1.4 条件控制可以嵌套 4.1.5 if语句的三元运算 4.1.6 国庆节快乐 4.1.1 理解条件控制 在日常生活中&#xff0c;我们常喜欢说如果, "如果怎么样&#xff0c;那么就会怎么样"。"如果&qu…

240930_CycleGAN循环生成对抗网络

240930_CycleGAN循环生成对抗网络 CycleGAN&#xff0c;也算是笔者记录GAN生成对抗网络的第四篇&#xff0c;前三篇可以跳转 240925-GAN生成对抗网络-CSDN博客 240929-DCGAN生成漫画头像-CSDN博客 240929-CGAN条件生成对抗网络-CSDN博客 在第三篇中&#xff0c;我们采用了p…