深入浅出:手把手教你实现顺序表

news2024/11/19 14:38:12

一、什么是顺序表

顺序表是一种数据结构,或者说,是数据在内存中存储和管理的一种方式。顺序表要求每个数据要从第一个位置开始,依次挨着放。这就很适合使用C语言中的数组来实现。

很多朋友可能会觉得,那有啥可以讲的?我们创建一个数组,在里面存储数据不就得了?其实没这么简单。这个数组要创建多大?如果创建太小,万一数据太多,不够存咋办?万一创建太大,却没这么多数据,那很多空间不就浪费了?所以,我们需要进行动态的内存管理。比如说,一开始就给4个空间,之后每次放满了就扩容,依次类推。

C语言里提供了动态内存管理的函数,分别是malloc,calloc,realloc和free。这些函数能够帮助我们很好地进行动态内存的管理。以上的这几个函数有一个特点,需要使用一个指针来指向这块动态管理的空间。除此之外,我们还需要两个变量,分别用来记录这块空间的大小,以及存储的有效数据的个数。综上,我们需要声明一个结构体来描述顺序表。


struct SeqList
{
    int* a;
    int size;
    int capacity;
};

其中,我们假设要存储的数据类型是int,所以需要一个int*的指针来管理这块空间。如果需要存储其他类型的数据,并且随时修改存储类型,可以使用typedef,用SLDateType来代替此处和下文中出现的int,这样方便以后修改存储类型。


typedef int SLDataType;

以上结构体中的size代表目前存储的有效数据的个数,一开始是0。而capacity则代表容量,也就是目前最多可以存储的数据个数。当size和capacity相等时,代表顺序表已满,此时就需要扩容。

需要说明的是,如果你嫌每次写struct SeqList很麻烦,也可以typedef一下。


typedef struct SeqList
{
    int* a;
    int size;
    int capacity;
}SL;

以下叙述中,我们假设已经创建了一个顺序表,并且拿到了它的地址psl。


SL sl;
SL* psl = &sl;

由于后面的操作都要对psl解引用,所以我们假设每次解引用前都断言了psl!=NULL。


assert(psl);

二、初始化

顺序表一开始没有存储任何数据,所以可以把先把结构体的内容都初始化成0。


psl->a = psl->size = psl->capacity = 0;

三、插入、删除

数组的下标是从0开始的,所以我们假定顺序表的下标也是从0开始。那么,我们如何在下标为pos的位置插入一个数据呢?其实很简单,只需要把pos及pos之后的位置向后挪动一格,此时pos位置就空出来了,就可以插入数据了。所以核心代码就一行,即如何挪动数据。我们需要知道起始位置是pos,往后挪动一格就到了pos+1。一共要挪动几个数据呢?举个例子,假设一共有10个数据,也就是size=10,假设pos是3,下标是从0开始的,pos前面的数据有0,1,2,总共3个数据,也就是说,pos前面的数据有pos个,那么pos及pos之后的数据就有size-pos个,这也是要挪动的数据的个数。我们使用memmove函数来挪动数据,注意不能使用memcpy,因为挪动前后的内存空间是有重叠的。


memmove(psl->a+pos+1, psl->a+pos, (psl->size-pos)*sizeof(int));

接着插入数据。


psl->a[pos] = x;
psl->size++;

这就完了吗?No!你忽略了一个重要的问题。一开始初始化时,psl为空,能直接解引用吗?还有万一size=capacity,能直接插入吗?所以每次插入前,都要检查一下容量是否充足,如果满了,要扩容!

检查容量是否充足很好办,如果size==capacity就满了,这包括两种情况,一种是capacity=size=0,另一种是随着size逐渐增长,size==capacity时就满了。

那如何扩容呢?这就可以使用realloc。注意当传给realloc的指针为NULL时,realloc的表现和malloc是一样的。所以我们可以把上面两种情况当做一种情况来处理。为了叙述方便,我们假设一开始给4个空间,后面每次都扩2倍,也就是说新的容量是:


int newCapacity = psl->capacity==0 ? 4 : 2*psl->capacity;

接着调用realloc函数:


int* tmp = (int*)realloc(psl->a, newCapacity*sizeof(int));

若tmp经过检查不为NULL,说明扩容成功。


psl->a = tmp;
psl->capacity = newCapacity;

知道了如何插入数据,删除数据也是同样的道理。只需要把pos位置之后的数据向前挪一格,就覆盖掉了pos位置的数据,相当于把pos位置的数据删除了。目标位置是pos,起始位置是pos+1,要挪动的数据个数是多少呢?在上面插入数据的讲解中,pos及pos之后的数据个数是size-pos,那么不包括pos的数据个数就是size-pos-1。


memmove(psl->a+pos, psl->a+pos+1, (size-pos-1)*sizeof(int));

最后不要忘了psl->size--。但是有个问题,如果一开始就没有数据,那就不能继续删了呀!所以删除之前要断言一下psl->size>0,才可以删除(但有了后面的讲解,其实不用断言这一点,具体原因后面说)。

其实,前面的讲述中漏掉了一点,那就是pos并不是任何值都可以的。在插入数据的时候,必须保证pos>=0 && pos<=psl->size,而在删除的时候,必须保证pos>=0 && pos<psl->size。pos>=0很好理解,因为下标从0开始。pos<size也很好理解,因为size表示有效数据个数。假设有6个数据,即size是6,下标就是0~5,pos就只能从这之间取。但是插入时为啥允许pos==size呢?还是假设有6个数据,size是6,已经有的数据下标是0~5,那如果是否允许在下标为6的位置插入呢?当然允许呀!因为在已经有的最后一个数据后面紧接着插入一个数据,并没有违反顺序表数据挨着挨着存储的原则。

由于删除顺序表的元素时有pos>=0,size>pos,故有size>0,所以不用断言这一点。

四、打印

只需要遍历这个数组然后打印即可。


for (int i = 0; i<psl->size; ++i)
{
    printf("%d ", psl->a[i]);
}
printf("\n");

五、查找、修改

查找也是遍历数组即可,非常简单。需要注意的是,pos必须要满足pos>=0 && pos<psl->size。具体原因,讲解插入删除时已经讲过。

如查找x:


for (int i = 0; i<psl->size; ++i)
{
    if (psl->a[i] == x)
        return i;
}

return -1; // 找不到就返回负数

修改也很简单,访问下标为pos的数据并且改掉即可。


psl->a[pos] = x;

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

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

相关文章

Shell - 加固系统配置

文章目录 #! /bin/bash # Function:对账户的密码的一些加固 read -p "设置密码最多可多少天不修改&#xff1a;" A read -p "设置密码修改之间最小的天数&#xff1a;" B read -p "设置密码最短的长度&#xff1a;" C read -p "设置密码失效…

C语言memcpy与memmove

C语言memcpy与memmove memcpy memcpy函数原型 void* memcpy(void* dst,const void* src,size_t size);//const修饰src,表示不应该修改src指向的数据memcpy用于实现数据的拷贝操作&#xff0c;将src往后的size字节数据拷贝到dst指向的空间 memcpy的实现&#xff1a; void*…

头歌MYSQL——课后作业1 数据库和数据表的建立、修改和删除

第1关&#xff1a;建立数据库 任务描述 本关任务&#xff1a;建立数据库 为了完成本关任务&#xff0c;你需要掌握&#xff1a; 如何创建数据库&#xff0c;显示已经建立的数据库 相关知识 创建数据库 创建数据库是在系统磁盘上划分一块区域用于数据的存储和管理。 命令格…

Android片段

如果你希望应用根据不同的环境有不同的外观和行为&#xff0c;这种情况下就需要片段&#xff0c;片段是可以由不同活动重用的模块化代码组件。 片段&#xff08;Fragment&#xff09;是活动&#xff08;Activity&#xff09;的一种模块化部分&#xff0c;表示活动中的行为或界面…

日本”闲鱼“Mercari煤炉是什么?如何做?

相信做跨境的小伙伴经常听到一个平台&#xff1a;日本煤炉。这是一个跨境电商平台&#xff0c;那么它是什么样的跨境电商平台呢&#xff1f;这个平台好做吗&#xff1f;如何卖货&#xff1f;带着这些问题&#xff0c;接下来小编为大家详细的讲解&#xff0c;帮助大家更好的更了…

开关电源传导发射

开关电源相较于传统的线性电源&#xff0c;具有工作效率高&#xff0c;体积小的优点&#xff0c;因此获得了广泛的应用。但是由于其内部开关管不停的通断&#xff0c;产生了大的du/dt&#xff0c;因此开关电源是产生传导发射的一个主要噪声源&#xff0c;并且由于与电源线直接连…

快速了解状态管理库Pinia及其使用方法

目录 1.pinia是什么 2.为什么要使用pinia 3.pinia的优点 4.pinia在项目中使用 ①创建一个使用pinia的Vue3项目 ②在页面使用store 1.pinia是什么 Pinia 起源于一次探索 Vuex 下一个迭代的实验&#xff0c;如果你学过Vue2&#xff0c;那么你一定使用过Vuex。Vuex在Vue2中主…

《让你的沟通结构化》考试试题及答案截图

中电金信新员工入职培训选修课《让你的沟通结构化》考试答案截图

基于STM32F103C8T6的系统板设计

针对兆易创新旗下型号GD32F103C8T6(兼容STM32F103C8T6)芯片设计的方案验证板,整板由micro USB供电通过1117稳压管稳压输出3.3V供电,中间配备唤醒按键和复位按键,两侧是从芯片引脚引出的IO口用于调试,其中有3.3V、5V电压选择,BOOT0模式选择,SWD调试接口,电源指示灯以及…

二、Mycat2 相关概念及读写分离

第三章 Mycat2 相关概念 3.1 概念描述 1、分库分表 按照一定规则把数据库中的表拆分为多个带有数据库实例,物理库,物理表访问路 径的分表。 解读&#xff1a;分库&#xff1a;一个电商项目&#xff0c;分为用户库、订单库等等。 分表&#xff1a;一张订单表数据数百万&#xff…

时序预测 | MATLAB实现基于QPSO-BiGRU、PSO-BiGRU、BiGRU时间序列预测

时序预测 | MATLAB实现基于QPSO-BiGRU、PSO-BiGRU、BiGRU时间序列预测 目录 时序预测 | MATLAB实现基于QPSO-BiGRU、PSO-BiGRU、BiGRU时间序列预测效果一览基本描述程序设计参考资料 效果一览 基本描述 1.时序预测 | MATLAB实现基于QPSO-BiGRU、PSO-BiGRU、BiGRU时间序列预测&a…

LoRA大模型加速微调和训练算法解读

理论 Lora( Low-Rank Adaotation)&#xff0c;低秩自适应模型微调的方法&#xff0c;它冻结预训练模型的权重&#xff0c;并将可训练的秩分解矩阵注入到transformer架构的每一层&#xff0c;从而大大减少下游任务的可训练参数的数量&#xff0c; 怎么微调下游任务:利用LoRA对…

1.Python操作txt文本

文章目录 1.Python读取一个txt文件的内容并将其写入到另一个txt文件2.Python读取一个未知编码的文件并将其设置为指定编码格式3.Python实现txt文件中字符串的替换 1.Python读取一个txt文件的内容并将其写入到另一个txt文件 # -*- encoding:gb2312 -*- import chardetdef read_…

WebSocket 协议及其使用案例

文章目录 前言一、初识 WebSocket 协议1.1 什么是 WebSocket 协议1.2 WebSocket 与 HTTP 的关系1.3 WebSocket 握手的过程1.4 WebSocket 解决了什么问题 二、WebSocket 数据帧格式2.1 WebSocket 数据帧格式图示2.2 各字段的详细说明 三、SpringBoot 项目中引入 WebSocket3.1 创…

Meta语言模型LLaMA解读:模型的下载部署与运行代码

文章目录 llama2体验地址模型下载下载步骤准备工作什么是Git LFS下载huggingface模型 模型运行代码 llama2 Meta最新语言模型LLaMA解读&#xff0c;LLaMA是Facebook AI Research团队于2023年发布的一种语言模型&#xff0c;这是一个基础语言模型的集合。 体验地址 体验地址 …

分布式锁实现一. 利用Mysql数据库update锁

文章目录 分布式锁1、什么是分布式锁&#xff1a;2、分布式锁应该具备哪些条件&#xff1a; 基于数据库的分布式锁代码传送代码运行 分布式锁 1、什么是分布式锁&#xff1a; 分布式锁&#xff0c;即分布式系统中的锁。在单体应用中我们通过锁解决的是控制共享资源访问的问题…

hp惠普光影精灵5笔记本HP Pavilion Gaming-15-dk0135tx原装出厂Win10系统

原厂系统自带所有驱动、出厂主题壁纸LOGO、Office办公软件、惠普电脑管家等预装程序 适用型号&#xff1a; 15-dk0011tx,15-dk0018tx,15-dk0019tx,15-dk0020tx,15-dk0021tx,15-dk0038tx 15-dk0039tx,15-dk0040tx,15-dk0041tx,15-dk0125tx,15-dk0126tx,15-dk0127tx 15-dk012…

Python Opencv实践 - 霍夫线检测(Hough Lines)

import cv2 as cv import numpy as np import matplotlib.pyplot as plt import randomimg cv.imread("../SampleImages/GreenBoard.jpg") print(img.shape) plt.imshow(img[:,:,::-1])#将图像转为二值图 gray cv.cvtColor(img, cv.COLOR_BGR2GRAY) plt.imshow(gra…

【【萌新的STM32学习25--- USART寄存器的介绍】】

萌新的STM32学习25- USART寄存器的介绍 STM32–USART寄存器介绍&#xff08;F1&#xff09; 控制寄存器1 &#xff08;CR1&#xff09; 位13&#xff1a; 使能USART UE 0&#xff1a; USART分频器和输出被禁止 1&#xff1a; USART模块使能 位12 &#xff1a; 配置8个数据位…

正中优配:股票xd什么意思

作为本钱市场中的重要一环&#xff0c;股票出资已经成为现代个人和组织出资的重要挑选之一。而在股票出资中&#xff0c;出资者常常会看到股票的价格上出现"xd"字样&#xff0c;这时候不少出资者就会疑问&#xff0c;这个"xd"到底是什么意思&#xff1f;对…