当前位置: 首页 > news >正文

C语言数据结构初阶(2)----顺序表

目录

1. 顺序表的概念及结构

2. 动态顺序表的接口实现

 2.1 SLInit(SL* ps) 的实现

2.2 SLDestory(SL* ps) 的实现

2.3 SLPrint(SL* ps) 的实现

2.4 SLCheckCapacity(SL* ps) 的实现

2.5 SLPushBack(SL* ps, SLDataType x) 的实现

2.6 SLPopBack(SL* ps) 的实现

2.7 SLPushFront(SL* ps, SLDataType x) 的实现

2.8 SLPopFront(SL* ps) 的实现

2.9 SLInsert(SL* ps, int pos, SLDataType x) 的实现

2.10 SLErase(SL* ps, int pos) 的实现

2.11 SLFind(SL* ps, SLDataType x) 的实现

3. 顺序表的缺点


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

1. 顺序表的概念及结构

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

2. 动态顺序表:使用动态开辟的数组存储。

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组如果数组如果太大了,会出现浪费的情况,如果定长数组太小了,则会出现不够用的情况。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

2. 动态顺序表的接口实现

下面是顺序表的头文件哈:SeqList.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int SLDataType;//一开始的空间
#define INIT_CAPACITY 4// 动态顺序表 -- 按需申请
typedef struct SeqList
{SLDataType* a;int size;     // 有效数据个数int capacity; // 空间容量
}SL;// 增删查改
void SLInit(SL* ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);
void SLCheckCapacity(SL* ps);void SLPushBack(SL* ps, SLDataType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
int SLFind(SL* ps, SLDataType x);

这个头文件里面的结构体需要好好理解一下的哦。SLDatatype* a,是指向动态开辟的数组的指针。size,是指顺序表中的元素个数。capacity,是指动态的数组有多大的空间。

 2.1 SLInit(SL* ps) 的实现

在创建顺序表的时候显然就是用上面的那个结构体创建,即:SL s。然后我们就要将结构体传过去对结构体进行初始化,这时显然就有两种传参的方式:直接传结构体 s 过去,这样做固然没有啥大的问题,但是嘞,我们都知道在传参时是需要将实参进行拷贝的,如果结构体本身越大,消耗的时间也就越多。所以在结构体传参的时候我们一般传结构体的指针。即,&s。初始化时不用做什么大事儿,只需要开辟一个小小的空间:INIT_CAPACITY (头文件中有该标识符的定义),将 size 和 capacity 赋值即可。

关于传参的问题请参考:http://t.csdn.cn/4GlPu

//顺序表的初始化
void SLInit(SL* ps)
{//断言提高代码的鲁棒性,因为后面有对ps指针的解引用,所以不能传空指针哈assert(ps);//开辟一个小小的空间ps->a = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);//必要性的检查if (ps->a == NULL){//如果开辟失败的话报出错误perror("malloc fail");return;}//size和capacity的初始化ps->size = 0;ps->capacity = INIT_CAPACITY;
}

2.2 SLDestory(SL* ps) 的实现

这个就是当顺序表使用完毕后必须调用的函数。因为顺序表的空间是在堆区上去申请的,如果说程序员不释放的话,就会出现内存泄漏的问题。虽然说这里的顺序表使用的空间不释放,在进程结束时操作系统会回收,但如果是跑在服务器上的程序,就会出问题的,所以说一定要养成好习惯。堆上开辟的空间必须手动释放哦!

//顺序表的销毁
void SLDestroy(SL* ps)
{assert(ps);//与malloc对应的freefree(ps->a);//养成好习惯,不要出现野指针ps->a = NULL;ps->capacity = ps->size = 0;
}

2.3 SLPrint(SL* ps) 的实现

这个是顺序表的打印函数哈,这个函数比较简单,只需要用一个变量打印size之前的数据即可。

//顺序表的打印
void SLPrint(SL* ps)
{assert(ps);//从头到size打印数据for (int i = 0; i < ps->size; ++i){printf("%d ", ps->a[i]);}printf("\n");
}

2.4 SLCheckCapacity(SL* ps) 的实现

我们往顺序表里面插数据的时候,显然可能存在没有剩余空间的时候。这时我们就需要扩容啦。

emm,扩容的时候新的空间应该选多大嘞,有多种选择哈,这里我们选则扩原来的两倍。

 我们都知道 realloc 在扩容的时候是有三种情况的:

1:扩容失败。这种情况不用讨论哈。

2:原地扩容,即从原空间的起始指针开始,还有新空间的大小还未被使用。此时 realloc 返回的指针就是原来的指针。

 3:异地扩容,异地扩容就是从原来的指针开始,没有你需要的空间能够分配给你,这时就会在堆区寻找空间足够的地方,然后将原来的数据拷贝到新的空间,并且销毁原来的空间,返回新的空间的起始地址。

 扩容之后更新一下 capacity 就可以啦!

//检查顺序表的容量
void SLCheckCapacity(SL* ps)
{assert(ps);//size == capacity 说明数据装满了,需要扩容if (ps->size == ps->capacity){SLDataType* tmp = (SLDataType*)realloc(ps->a, sizeof(SLDataType) * ps->capacity * 2);if (tmp == NULL){//这里的道理根SLInit中的一样perror("realloc fail");return;}//这里一定要将tmp赋值给ps->a,因为可能异地扩容ps->a = tmp;//这里我们是选用数据满了扩容两倍这种方式的ps->capacity *= 2;}
}

2.5 SLPushBack(SL* ps, SLDataType x) 的实现

这个函数只需要注意一下尾插的时候检查一下顺序表是不是满了就行。尾插就是在数组下标为size的地方插入数据即可,插入数据后 size++。不理解可以看看前面的图。

//顺序表的尾插
void SLPushBack(SL* ps, SLDataType x)
{assert(ps);//检查容量,不足则扩容SLCheckCapacity(ps);ps->a[ps->size++] = x;}

2.6 SLPopBack(SL* ps) 的实现

这是顺序表的尾删哈,这个就更简单了,只要将 size-- 就行,原因就是我们访问数据只能访问到下标小于size的哒。还有一点就是如果顺序表为空,即size == 0 是不允许删除数据的哦!

//顺序表的尾删
void SLPopBack(SL* ps)
{assert(ps);//顺序表为空不允许删除数据哦assert(ps->size > 0);ps->size--;}

2.7 SLPushFront(SL* ps, SLDataType x) 的实现

这是顺序表的头插函数哈,这里就需要将数据整体向后移动一位,才可以进行头插哦,记得一定要从最后一个数据开始移动哦!!头插完毕记得让size++哦!既然是插入元素也要记得检查顺序表的容量哦!

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

2.8 SLPopFront(SL* 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--;
}

2.9 SLInsert(SL* ps, int pos, SLDataType x) 的实现

这是顺序表的指定位置插入哦,0 <= pos <= size 的哦,pos的输入必须合法。这里的插入和头插的逻辑类似,也需要移动数据,从后往前移动,到pos的位置为止。然后插入数据 x,同时size++,插入数据都必须检查容量的。

//顺序表指定位置的插入
void SLInsert(SL* ps, int pos, SLDataType x)
{assert(ps);//pos输入必须合法assert(pos >= 0 && pos <= ps->size);//检查容量SLCheckCapacity(ps);int end = ps->size - 1;while (end >= pos){ps->a[end + 1] = ps->a[end];--end;}ps->a[pos] = x;ps->size++;
}

2.10 SLErase(SL* ps, int pos) 的实现

这里的逻辑就和头删的数据移动差不多的,从pos的位置开始,从前往后移动。移动完了记得让 size--。这里同样需要检查 pos 的合法性。但是就不用检查顺序表是否为空啦,因为当顺序为空的时候 size == 0,pos无论输入什么值都会断言失败的。

//删除指定位置的数据
void SLErase(SL* ps, int pos)
{assert(ps);//pos输入合法assert(pos >= 0 && pos < ps->size);int begin = pos + 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];++begin;}ps->size--;
}

2.11 SLFind(SL* ps, SLDataType x) 的实现

//顺序表查找指定元素,返回下标,不存在返回-1
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;
}

3. 顺序表的缺点

1. 中间/头部的插入删除,时间复杂度为O(N)。
2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的时间消耗。
3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如200,我们再继续插入了5个数据,后面没有数据插入了,就会浪费空间。
思考:如何解决以上问题呢?下期的链表可以帮助大家解决其中的一部分问题。

相关文章:

C语言数据结构初阶(2)----顺序表

目录 1. 顺序表的概念及结构 2. 动态顺序表的接口实现 2.1 SLInit(SL* ps) 的实现 2.2 SLDestory(SL* ps) 的实现 2.3 SLPrint(SL* ps) 的实现 2.4 SLCheckCapacity(SL* ps) 的实现 2.5 SLPushBack(SL* ps, SLDataType x) 的实现 2.6 SLPopBack(SL* ps) 的实现 2.7 SLP…...

K8S常用命令速查手册

K8S常用命令速查手册一. K8S日常维护常用命令1.1 查看kubectl版本1.2 启动kubelet1.3 master节点执行查看所有的work-node节点列表1.4 查看所有的pod1.5 检查kubelet运行状态排查问题1.6 诊断某pod故障1.7 诊断kubelet故障方式一1.8 诊断kubelet故障方式二二. 端口策略相关2.1 …...

Linux系统下命令行安装MySQL5.6+详细步骤

1、因为想在腾讯云的服务器上创建自己的数据库&#xff0c;所以我在这里是通过使用Xshell 7来连接腾讯云的远程服务器&#xff1b; 2、Xshell 7与服务器连接好之后&#xff0c;就可以开始进行数据库的安装了&#xff08;如果服务器曾经安装过数据库&#xff0c;得将之前安装的…...

13.STM32超声波模块讲解与实战

目录 1.超声波模块讲解 2.超声波时序图 3.超声波测距步骤 4.项目实战 1.超声波模块讲解 超声波传感器模块上面通常有两个超声波元器件&#xff0c;一个用于发射&#xff0c;一个用于接收。电路板上有4个引脚&#xff1a;VCC GND Trig&#xff08;触发&#xff09;&#xff…...

逆向之Windows PE结构

写在前面 对于Windows PE文件结构&#xff0c;个人认为还是非常有必要掌握和了解的&#xff0c;不管是在做逆向分析、免杀、病毒分析&#xff0c;脱壳加壳都是有着非常重要的技能。但是PE文件的学习又是一个非常枯燥过程&#xff0c;希望本文可以帮你有一个了解。 PE文件结构…...

ACL是什么

目录 一、ACL是什么 二、ACL的使用&#xff1a;setacl与getacl 1&#xff09;针对特定使用者的方式&#xff1a; 1. 创建acl_test1后设置其权限 2. 读取acl_test1的权限 2&#xff09;针对特定群组的方式&#xff1a; 3&#xff09;针对有效权限 mask 的设置方式&#xf…...

操作系统核心知识点整理--内存篇

操作系统核心知识点整理--内存篇按段对内存进行管理内存分区内存分页为什么需要多级页表TLB解决了多级页表什么样的缺陷?TLB缓存命中率高的原理是什么?段页结合: 为什么需要虚拟内存&#xff1f;虚拟地址到物理地址的转换过程段页式管理下程序如何载入内存&#xff1f;页面置…...

从零开始学习iftop流量监控(找出服务器耗费流量最多的ip和端口)

一、iftop是什么iftop是类似于top的实时流量监控工具。作用&#xff1a;监控网卡的实时流量&#xff08;可以指定网段&#xff09;、反向解析IP、显示端口信息等官网&#xff1a;http://www.ex-parrot.com/~pdw/iftop/二、界面说明>代表发送数据&#xff0c;< 代表接收数…...

第一篇博客------自我介绍篇

目录&#x1f506;自我介绍&#x1f506;学习目标&#x1f506;如何学习单片机Part 1 基础理论知识学习Part 2 单片机实践Part 3 单片机硬件设计&#x1f506;希望进入的公司&#x1f506;结束语&#x1f506;自我介绍 Hello!!!我是一名即已经步入大二的计算机小白。 --------…...

No suitable device found for this connection (device lo not available(网络突然出问题)

当执行 ifup ens33 出现错误&#xff1a;[rootlocalhost ~]# ifup ens33Error: Connection activation failed: No suitable device found for this connection (device lo not available because device is strictly unmanaged).1解决办法&#xff1a;[rootlocalhost ~]# chkc…...

【算法设计技巧】分治算法

分治算法 用于设计算法的另一种常用技巧为分治算法(divide and conquer)。分治算法由两部分组成&#xff1a; 分(divide)&#xff1a;递归解决较小的问题(当然&#xff0c;基准情况除外)治(conquer)&#xff1a;然后&#xff0c;从子问题的解构建原问题的解。 传统上&#x…...

已解决kettle新建作业,点击保存抛出异常Invalid state, the Connection object is closed.

已解决kettle新建作业&#xff0c;点击保存进资源数据库抛出异常Invalid state, the Connection object is closed.的解决方法&#xff0c;亲测有效&#xff01;&#xff01;&#xff01; 文章目录报错问题报错翻译报错原因解决方法联系博主免费帮忙解决报错报错问题 一个小伙伴…...

【设计模式】 工厂模式介绍及C代码实现

【设计模式】 工厂模式介绍及C代码实现 背景 在软件系统中&#xff0c;经常面临着创建对象的工作&#xff1b;由于需求的变化&#xff0c;需要创建的对象的具体类型经常变化。 如何应对这种变化&#xff1f;如何绕过常规的对象创建方法(new)&#xff0c;提供一种“封装机制”来…...

深入浅出PaddlePaddle函数——paddle.arange

分类目录&#xff1a;《深入浅出PaddlePaddle函数》总目录 相关文章&#xff1a; 深入浅出TensorFlow2函数——tf.range 深入浅出Pytorch函数——torch.arange 深入浅出PaddlePaddle函数——paddle.arange 语法 paddle.arange(start0, endNone, step1, dtypeNone, nameNone…...

X86 ATT常用寄存器及其操作指令

X86 AT&T常用寄存器及其操作指令 常用寄存器 esp寄存器&#xff1a;当我们需要访问堆栈帧中的变量时&#xff0c;可以使用esp寄存器来获取堆栈帧的基址&#xff0c;以便能够正确地访问堆栈帧中的变量。ebp寄存器&#xff1a;当我们需要调用一个函数时&#xff0c;可以使用…...

Kotlin 高端玩法之DSL

如何在 kotlin 优雅的封装匿名内部类&#xff08;DSL、高阶函数&#xff09;匿名内部类在 Java 中是经常用到的一个特性&#xff0c;例如在 Android 开发中的各种 Listener&#xff0c;使用时也很简单&#xff0c;比如&#xff1a;//lambda button.setOnClickListener(v -> …...

理光M2701复印机载体初始化方法

理光M2701基本参数&#xff1a; 产品类型&#xff1a;数码复合机 颜色类型&#xff1a;黑白 复印速度&#xff1a;单面&#xff1a;27cpm 双面&#xff1a;16cpm 涵盖功能&#xff1a;复印、打印、扫描 网络功能&#xff1a;支持无线、有线网络打印 接口类型&#xff1a;USB2.0…...

2.25Maven的安装与配置

一.Mavenmaven是一个Java世界中,非常知名的"工程管理工具"/构建工具"核心功能:1.管理依赖在进行一个A 操作之前,要先进行一个B操作.依赖有的时候是很复杂的,而且是嵌套的2.构建/编译(也是在调用jdk)3. 打包把java代码给构建成jar或者warjar就是一个特殊的压缩包…...

《英雄编程体验课》第 12 课 | 递归

文章目录 零、写在前面一、搜索算法的原理二、深度优先搜索三、基于DFS的记忆化搜索四、基于DFS的剪枝五、基于DFS的A*(迭代加深,IDA*)零、写在前面 该章节节选自 《夜深人静写算法》,主要讲解最基础的搜索算法,其中用到的思想就是递归,当然,如果已经对本套体验课了如指…...

35测试不如狗?是你自己技术不够的怨怼罢了

一、做软件测试怎么样&#xff1f; 引用著名软件测试专家、清华大学郑人杰教授的说法&#xff1a;软件测试工程师是一个越老越吃香的职业。 其中就表达了软件测试工作相对稳定、对年龄没有限制、而且随着项目经验的不断增长和对行业背景的深入了解&#xff0c;会越老越吃香。…...

【代码训练营】day42 | 1049. 最后一块石头的重量 II 494. 目标和 474.一和零

所用代码 java 最后一块石头的重量II LeetCode 1049 题目链接&#xff1a;最后一块石头的重量II LeetCode 1049 - 中等 思路 无。 把石头分成重量总和近似两堆&#xff0c;然后两堆石头相撞&#xff0c;剩下的就是最小的石头。每个石头只能用一次&#xff0c;01背包&#xf…...

Golang协程常见面试题

协程面试题交替打印奇数和偶数N个协程打印1到maxVal交替打印字符和数字交替打印字符串三个协程打印ABCChannel练习交替打印奇数和偶数 下面让我们一起来看看golang当中常见的算法面试题 使用两个goroutine交替打印1-100之间的奇数和偶数, 输出时按照从小到大输出. 方法一&…...

种群多样性:智能优化算法求解基准测试函数F1-F23种群动态变化图(视频)

智能优化算法求解基准测试函数F1种群动态变化图智能优化算法求解基准测试函数F2种群动态变化图智能优化算法求解基准测试函数F3种群动态变化图智能优化算法求解基准测试函数F4种群动态变化图智能优化算法求解基准测试函数F5种群动态变化图智能优化算法求解基准测试函数F6种群动…...

Qt 中的XML

XML的基本介绍&#xff1a; 在前端开发中&#xff1a;HTML是用来显示数据&#xff0c;而XML是用来传输和存储数据的 XML 指可扩展标记语言&#xff08;EXtensible Markup Language&#xff09;XML 是一种标记语言&#xff0c;很类似 HTMLXML 的设计宗旨是传输数据&#xff0c;而…...

网络应用之URL

URL学习目标能够知道URL的组成部分1. URL的概念URL的英文全拼是(Uniform Resoure Locator),表达的意思是统一资源定位符&#xff0c;通俗理解就是网络资源地址&#xff0c;也就是我们常说的网址。2. URL的组成URL的样子:https://news.163.com/18/1122/10/E178J2O4000189FH.html…...

【Linux】重定向原理dup2缓冲区

文章目录重定向原理输出重定向关于FILE解释输出重定向原理追加重定向输入重定向dup2缓冲区语言级别的缓冲区内核缓冲区重定向原理 重定向的本质就是修改文件描述符下标对应的struct file*的内容 输出重定向 输出重定向就是把本来应该输出到显示器的数据重定向输出到另一个文…...

ROG配置ubuntu20.04.5双系统要点

win11ubuntu20.04.5 1. BIOS设置 开机长按F2进入bios设置&#xff0c;修改advanced参数&#xff1a; boot -> 关闭fast bootsecurity -> 关闭secure boot设置VMD controller为Disabled&#xff08;其他电脑是修改硬盘的SATA和ACHI模式&#xff09;。但是改了之后windo…...

机械革命旷世G16电脑开机变成绿屏了无法使用怎么办?

机械革命旷世G16电脑开机变成绿屏了无法使用怎么办&#xff1f;最近有用户使用的机械革命旷世G16电脑一开机之后&#xff0c;电脑屏幕就变成了绿色的&#xff0c;无法进行任何的操作。出现这个问题可能是因为电脑中病毒了&#xff0c;或者是系统出现故障。我们可以通过U盘来重新…...

python中关于time模块的讲解---指定格式时间字符串转为时间戳

本文章可以解决任意字符串格式时间转为时间戳 返回json格式 可以在此基础上进行修改 时间格式控制符 说明 %Y 四位数的年份&#xff0c;取值范围为0001~9999,如1900 %m 月份&#xff08;01~12&#xff09;&#xff0c;例如10 %d 月中的一天&#xff08;01~31&#xff09;例…...

MySql存储引擎与索引

MySql引擎 存储引擎是具体操作数据的地方&#xff0c;是一种对数据存储的技术与其配套的功能 不同存储引擎所采用存储的方式的不同&#xff0c;并且索引技巧与锁定水平也不同 根据业务的需求灵活的选择存储引擎即可满足的实际的需要 Innodb Innodb是MySql中的默认安装的引擎…...