顺序表——重置版

news2024/9/29 11:38:16

本期我们来实现数据结构的顺序表(这个之前写过一次,不过本期和之前可能会略有不同,但大体相同),大家可以看一下我们之前完成的顺序表

(6条消息) 顺序表及其多种接口的实现_顺序表类中实现接口方法_KLZUQ的博客-CSDN博客

目录

顺序表的结构

顺序表的初始化

顺序表的销毁

尾插

尾删

打印顺序表的元素

扩容

头插

头删

任意位置插入

任意位置删除

查找

realloc相关知识

完整代码


我们继续用工程化的写法来保证好的代码习惯

顺序表的结构

我们仍然是先写出顺序表的结构

typedef int SLDataType;
#define INIT_CAPACITY 10 //初始容量
typedef struct SeqList {
	SLDataType* a;
	int size;//有效数据个数 
	int capacity;//空间容量
}SL;

 因为顺序表大小的原因,开多了浪费,开少了不够用,所以我们需要定义一些变量来帮助我们对顺序表的大小进行调整

顺序表的初始化

void SLInit(SL* ps) {//初始化
	assert(ps);
	ps->a = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);
	if (ps->a == NULL) {
		perror("malloc fail");
		return;
	}
	ps->size = 0;
	ps->capacity = INIT_CAPACITY;
}

初始化参数我们需要传顺序表这个结构体的指针,然后使用malloc开辟空间给顺序表,这个空间就是我们用来存储数据的,同时我们要判断是否开辟成功,失败时我们用perror来返回错误信息即可,开辟成功后,我们将有效数据个数置0,容量置为我们设置的初始容量

第一行的断言是因为我们传入的是顺序表这个结构体的指针,是不可能为空的,所以需要断言,而顺序表里的内容是否为空是由size来进行决定的

顺序表的销毁

void SLDestory(SL* ps) {//销毁
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}

顺序表的销毁我们free的是ps->a,而不是直接free掉ps,然后我们将ps置为空即可

尾插

void SLPushBack(SL* ps, SLDataType x)//尾插
{
	assert(ps);
	if (ps->size == ps->capacity) {//扩容
		SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2*sizeof(SLDataType));
		if (tmp == NULL) {
			perror("realloc fail");
			return;
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
	ps->a[ps->size++] = x;
}

尾插前我们需要对容量进行判断,如果不够就需要先扩容,我们这里扩容扩二倍,接着把数据放入数组里即可(我们的size是从0开始的,也就是说size的位置是我们当前存放数据最后一个的下一个位置)

尾删

void SLPopBack(SL* ps)//尾删
{
    assert(ps);
	//严格的判断
	//assert(ps->size>0);
	//温柔的判断
	if (ps->size == 0) {
		return;
	}
	ps->size--;
}

因为是顺序表,我们使用size来控制当前数据个数,所以直接size-1即可,我们不需要将这里的数据置为0,因为没有必要,而且我们也不能释放空间,因为这是数组,是连续的空间,当然在删除数据前,我们要先判断数组是否为空,这里我们有两种方法,一种是用assert直接断言,另一种是当作无事发生(更推荐assert一些)

打印顺序表的元素

有了尾插尾删,我们需要对程序进行测试,所以我们对顺序表的元素进行打印

void SLPrint(SL* ps) {//打印
	assert(ps);
	for (int i = 0; i < ps->size; i++) {
		printf("%d->", ps->a[i]);
	}
	printf("NULL\n");
}

扩容

我们在写头插时,发现插入都需要先判断是否需要扩容,所以我们把扩容代码提取出来封装为一个函数方便后续使用

void SLCheckCapaicty(SL* ps)//扩容
{
	assert(ps);
	if (ps->size == ps->capacity) {//扩容
		SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));
		if (tmp == NULL) {
			perror("realloc fail");
			return;
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
}

头插

void SLPushFront(SL* ps, SLDataType x)//头插
{
	assert(ps);
	SLCheckCapaicty(ps);
	int end = ps->size - 1;
	while (end>=0) {
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	ps->a[0] = x;
	ps->size++;
}

头插的效率不高,需要挪动后续所有元素,如果有n个元素,我们要插入n个元素,时间复杂度就是n^2了,而尾插n个数据的数据复杂度是n,这是非常恐怖的,比如我们要插入1w个数据,那么头插就是1w*1w了,而尾插是1w,所以我们要避免使用头插

头删

void SLPopFront(SL* ps)//头删
{
	assert(ps);
	assert(ps->size > 0);
	int begin = 1;
	while (begin < ps->size) {
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

如果size为0,那么顺序表为空,不能进行删除,删除时我们只需将a[0]之后的元素向前挪动即可,接着size-1,同样的,头删的效率也很低,时间复杂度也是n^2,所以我们也要少用头删

任意位置插入

void SLInsert(SL* ps, int pos, SLDataType x)//任意位置插入
{
	assert(ps);
	assert(pos>=0 && pos<=ps->size);
	SLCheckCapaicty(ps);
	int end = ps->size - 1;
	while (end>=pos) {
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;
}

如果我们想在顺序表中间某个位置插入,就可以使用该函数,因为是插入,所以也需要先判断是否需要扩容,另外,我们传入的pos是位置,所以要符合顺序表元素的个数,所以要断言一下,下面的插入代码和头插几乎一样

任意位置删除

void SLErase(SL* ps, int pos)//任意位置删除
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	int begin = pos + 1;
	while (begin < ps->size) {
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

这里的断言和任意位置插入稍有不同,我们发现pos<ps->szie,而不能等于,而且我们不需要检查size是否大于0,因为pos会间接检查,因为size不可能为负数,而pos要大于等于0

查找

int SLFind(SL* ps, SLDataType x)//查找
{
	assert(ps);
	for (int i = 0; i < ps->size; i++) {
		if (ps->a[i] == x) {
			return i;
		}
	}
	return -1;
}

任意位置的插入和删除,一般是配合查找来使用的,查找返回的是下标,找不到时返回-1

realloc相关知识

最后我们在补充一点其他的只是,我们的顺序表扩容时使用了realloc函数,而realloc函数分配空间扩容会分为两种,一种是原地扩容,另一种是异地扩容,原地扩容就是将当前位置的后续空间使用权也分配给我们,而异地扩容则是新找了一块空间将使用权分配给我们,然后把原来的空间使用权归还给操作系统,当我们扩容小的时候,一般是原地扩容,但是当扩容次数较多时,后续空间会不足,就会进行异地扩容,找一块更大的空间给我们,异地扩容的效率是比原地扩容低很多的,异地扩容不仅要找一块新的空间,还要把原空间里的数据给拷贝过来,再释放原空间

完整代码

最后,在这里附上全部代码

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int SLDataType;
#define INIT_CAPACITY 10 //初始容量
typedef struct SeqList {
	SLDataType* a;
	int size;//有效数据个数 
	int capacity;//空间容量
}SL;

void SLInit(SL* ps);//初始化
void SLDestory(SL* ps);//销毁
void SLPrint(SL* ps);//打印
void SLPushBack(SL* ps,SLDataType x);//尾插
void SLPushFront(SL* ps, SLDataType x);//头插
void SLPopBack(SL* ps);//尾删
void SLPopFront(SL* ps);//头删
void SLCheckCapaicty(SL* ps);//扩容
void SLInsert(SL* ps, int pos, SLDataType x);//任意位置插入
void SLErase(SL* ps, int pos);//任意位置删除
int SLFind(SL* ps, SLDataType x);//查找

 

#include "SeqList.h"

void SLInit(SL* ps) {//初始化
	assert(ps);
	ps->a = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);
	if (ps->a == NULL) {
		perror("malloc fail");
		return;
	}
	ps->size = 0;
	ps->capacity = INIT_CAPACITY;
}

void SLCheckCapaicty(SL* ps)//扩容
{
	assert(ps);
	if (ps->size == ps->capacity) {//扩容
		SLDataType* tmp = (SLDataType*)realloc(ps->a, ps->capacity * 2 * sizeof(SLDataType));
		if (tmp == NULL) {
			perror("realloc fail");
			return;
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
}

void SLPrint(SL* ps) {//打印
	assert(ps);
	for (int i = 0; i < ps->size; i++) {
		printf("%d->", ps->a[i]);
	}
	printf("NULL\n");
}

void SLDestory(SL* ps) {//销毁
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}

void SLPushBack(SL* ps, SLDataType x)//尾插
{
	assert(ps);
	SLCheckCapaicty(ps);
	ps->a[ps->size++] = x;
}
void SLPushFront(SL* ps, SLDataType x)//头插
{
	assert(ps);
	SLCheckCapaicty(ps);
	int end = ps->size - 1;
	while (end>=0) {
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	ps->a[0] = x;
	ps->size++;
}
void SLPopBack(SL* ps)//尾删
{
	assert(ps);
	//严格的判断
	assert(ps->size>0);
	//温柔的判断
	/*if (ps->size == 0) {
		return;
	}*/
	ps->size--;
}
void SLPopFront(SL* ps)//头删
{
	assert(ps);
	assert(ps->size > 0);
	int begin = 1;
	while (begin < ps->size) {
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

int SLFind(SL* ps, SLDataType x)//查找
{
	assert(ps);
	for (int i = 0; i < ps->size; i++) {
		if (ps->a[i] == x) {
			return i;
		}
	}
	return -1;
}

void SLInsert(SL* ps, int pos, SLDataType x)//任意位置插入
{
	assert(ps);
	assert(pos>=0 && pos<=ps->size);
	SLCheckCapaicty(ps);
	int end = ps->size - 1;
	while (end>=pos) {
		ps->a[end + 1] = ps->a[end];
		--end;
	}
	ps->a[pos] = x;
	ps->size++;
}
void SLErase(SL* ps, int pos)//任意位置删除
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	int begin = pos + 1;
	while (begin < ps->size) {
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

以上就是本期全部内容,希望大家可以有所收获

如有错误,还请指正

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

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

相关文章

Linux环境下验证python项目

公司大佬开发的python rpa跑数项目&#xff0c;Windows运行没问题后&#xff0c;需要搭建一个linux环境进行验证&#xff0c;NOW START&#xff01; Install VMware官网 下载好之后打开按步骤安装 最后一步会让填许可证&#xff08;密钥&#xff09;&#xff0c;这里自行百…

Meta开放小模型LLaMA,性能超过GPT-3

论文地址&#xff1a;https://research.facebook.com/file/1574548786327032/LLaMA--Open-and-Efficient-Foundation-Language-Models.pdf 介绍 LLaMA&#xff0c;是Meta AI最新发布的一个从7B到65B参数的基础语言模型集合。在数以万亿计的token上训练模型&#xff0c;并表明…

运动跑步耳机哪种最好、5款最好用的运动耳机推荐

而作为一名运动爱好者&#xff0c;我非常喜欢在运动时听音乐&#xff0c;简直不要太轻松&#xff01;不过在换了多款蓝牙耳机之后&#xff0c;我终于找到了几款非常适合运动的耳机&#xff0c;戴着它们运动&#xff0c;不仅不会出现不适感&#xff0c;还能享受清晰动听音乐&…

多个AOP修饰同一个方法

1、背景 之前的文章中&#xff0c;有网友提出了一个问题&#xff0c;同一个方法用多个AOP修饰&#xff0c;执行顺序是怎样的&#xff1f; 好问题&#xff0c;之前没有关注过&#xff0c;这里写一个demo跑一下看看 同时有一个衍生问题&#xff0c;多个AOP修饰&#xff0c;会生…

Linux常用命令--进程和计划任务管理

一、程序和进程的关系 1、程序 ①保存在硬盘、光盘等介质中的可执行代码和数据 ②静态保存的代码 2、进程 ①在cpu及内存中运行及进程代码 ②动态执行的代码 ③父&#xff08;fork&#xff09;、子进程&#xff0c;每个程序可以创建一个或多个进程 父进程和子进程的区别&am…

springboot如何获取websocket的header头信息

websocket协议与http协议类似&#xff0c;也有属于自己的头信息&#xff0c;如下图所示&#xff0c;为postman在连接时自定义的header&#xff1a; 那么在后端中&#xff0c;如何像http的HttpServletRequest一样来获取这个头信息的内容呢? 自定义一个WebSocket配置类&#xff…

【LeetCode】剑指 Offer 19. 正则表达式匹配 p124 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/zheng-ze-biao-da-shi-pi-pei-lcof/ 1. 题目介绍&#xff08;19. 正则表达式匹配&#xff09; 请实现一个函数用来匹配包含. 和*的正则表达式。模式中的字符.表示任意一个字符&#xff0c;而’*表示它前面的字符可以出现任意…

图解LeetCode——剑指 Offer 21. 调整数组顺序使奇数位于偶数前面

一、题目 输入一个整数数组&#xff0c;实现一个函数来调整该数组中数字的顺序&#xff0c;使得所有奇数在数组的前半部分&#xff0c;所有偶数在数组的后半部分。 二、示例 2.1> 示例&#xff1a; 【输入】nums [1,2,3,4] 【输出】[1,3,2,4] 【注】[3,1,2,4] 也是正确的…

基于vscode创建SpringBoot项目,连接postgresql数据库

1、Vue下载安装步骤的详细教程(亲测有效) 1_水w的博客-CSDN博客 2、Vue下载安装步骤的详细教程(亲测有效) 2 安装与创建默认项目_水w的博客-CSDN博客 3、基于vscode开发vue项目的详细步骤教程_水w的博客-CSDN博客 4、基于vscode开发vue项目的详细步骤教程 2 第三方图标库FontAw…

最新的Windows docker安装方法

什么是Docker&#xff1f;关于Docker的相关概述&#xff0c;请看&#xff1a;Docker_面向架构编程的博客-CSDN博客在Windows10 or Windows11中安装docker主要就两步&#xff1a;1.安装wsl22. 安装docker一、安装WSL2安装wslwsl --install然后重启一下电脑在cmd窗口可以查看自己…

如何使用CVE-Tracker随时获取最新发布的CVE漏洞信息

关于CVE-Tracker CVE- Tracker是一款功能强大的CVE漏洞信息收集和更新工具&#xff0c;该工具基于自动化ps脚本实现其功能&#xff0c;可以帮助广大研究人员轻松获取到最新发布的CVE漏洞信息。 CVE-Tracker采用PowerShell开发&#xff0c;可以在操作系统启动的时候自动运行Mi…

计算机组成原理4小时速成5:系统总线,总线分类,数据总线,地址总线,控制总线,总线传输率

计算机组成原理4小时速成5&#xff1a;系统总线&#xff0c;总线分类&#xff0c;数据总线&#xff0c;地址总线&#xff0c;控制总线&#xff0c;总线传输率 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学…

华为6面,测试岗报价11k,HR说我不尊重华为,他们没有那么低薪资岗位?

在不知道一个公司的普遍薪资水平的时候&#xff0c;很多面试者不敢盲目的开价&#xff0c;但就因为这样可能使得面试官怀疑你的能力。一位网友就在网上诉说了自己的经历&#xff0c;男子是一位测试员&#xff0c;已经有九年的工作经历了&#xff0c;能力自己觉得还不错。 因为…

matlab-初学

初次学习了解matlab的相关知识&#xff0c;跟着b站博主学习的&#xff0c;仅此记录学习过程的笔记与感悟。命令行小常识1.命令行给变量赋值&#xff0c;回车即运行一行。2.逗号反馈这一行所有的变量结果&#xff1b;分号则不反馈&#xff0c;单实际变量值已经改变(只是不在下方…

22- estimater使用 (TensorFlow系列) (深度学习)

知识要点 estimater 有点没理解透 数据集是泰坦尼克号人员幸存数据. 读取数据&#xff1a;train_df pd.read_csv(./data/titanic/train.csv) 显示数据特征&#xff1a;train_df.info() 显示开头部分数据&#xff1a;train_df.head() 提取目标特征&#xff1a;y_train tr…

Web前端:四大Web应用开发趋势和技术

就像其他行业一样&#xff0c;web应用程序开发每年都会经历巨大的变化。就像人们说的&#xff0c;变化是技术中唯一不变的东西。因此&#xff0c;我们这里有一些你可以期待的市场变化。Web应用开发趋势和技术1.市场对聊天机器人和人工智能寄予厚望已经说过很多次&#xff0c;也…

java 面试

面试目录概述需求&#xff1a;设计思路实现思路分析1.面试概要参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for change,challenge Survive. happy f…

JSTL核心库的简单使用

JSTL核心库的简单使用 7.1考试重点 7.1.1c:out输出数据 考试重点就是c的相关的 jar包下载地址:Apache Tomcat - Apache Taglibs Downloads 看会典型应用就可以<% page contentType"text/html;charsetUTF-8" language"java" %> <% taglib uri"…

DolphinDB 通过 Telegraf + Grafana 实现设备指标的采集监控和展示

基于原始数据采集的可视化监控是企业确保设备正常运行和安全生产的重要措施。本文详细介绍了如何从DolphinDB 出发&#xff0c;借助 Telegraf 对设备进行原始数据采集&#xff0c;并通过 Grafana 实现数据的可视化&#xff0c;从而实现设备指标的实时监控。1. 概览Telegraf 是 …

Mybatis-plus逻辑删除更新字段

MybatisPlus版本 <dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version> </dependency> <dependency><groupId>com.baomidou</groupId&g…