[数据结构]顺序表
1、顺序表的概念及结构
1.1 线性表
线性表( linear list )是n个具有相同特性的数据元素的有限序列。 线性表是⼀种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。案例:蔬菜分为绿叶类、⽠类、菌菇类。线性表指的是具有部分相同特性的⼀类数据结构的集合
2、顺序表分类
2.1顺序表和数组的区别
2.2顺序表分类
1.静态顺序表:
概念:使用定长数组存储元素
代码示例:
typrdef int SLDataType;
#define N 8
typedef struct SeqList
{SLDataType a[N];//定长数组int size; //有效数据个数
}SL;
这就是一个静态顺序表,它又一定的缺陷。
2.动态顺序表
它的特点是:按需申请
3.动态顺序表的实现
我们首先创建相应的头文件和程序文件
![]()
我们现在头文件中,引用头文件,定义所需要的结构体和函数
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLDataType;typedef struct SeqList
{SLDataType* arr; //存储数据的底层结构int capacity; //记录顺序表的空间大小int size; //记录顺序表当前有效的数据个数
}SL;
//初始化:
void SLInit(SL* ps);
//销毁
void SLDestroy(SL* ps);
//顺序表的头部 / 尾部插入
void SLPushFront(SL* ps, SLDataType x);
void SLPushBack(SL* ps, SLDataType x);
//顺序表的头部 / 尾部删除
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);//打印
void SLPrint(SL* ps);
//删除指定位置的值
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);
我们先定义一个动态顺序表

注意:这行代码是为了设定我们的数据类型
1.初始化
接下来我们要初始化我们的顺序表。所以我们定义了这个函数

接着我们去源文件写完这个函数,让指针指向NULL大小设定为0完成初始化
void SLInit(SL* ps)
{ps->arr = NULL;ps->size = ps->capacity = 0;
}
写完了初始化我们可以开始写功能
首先就是头插和尾插

我们接着完善
2.头插
我们先来写头插函数
void SLPushFront(SL* ps, SLDataType x)
首先我们来思考以下问题,一个数组如何头插,以及目前的内存大小能否插入新的数据
假设足够:

数组头插,我们一般将数组的各个元素后移一位然后将数组arr[0]赋值成我们要插入的数据
void SLPushFront(SL* ps, SLDataType x)
{assert(ps);
for (int i = ps->size; i > 0; i--) //i = 1{ps->arr[i] = ps->arr[i - 1]; //ps->arr[1] = ps->arr[0]}ps->arr[0] = x;ps->size++;
}
我们不难写出这个函数但是它对吗?
显然存在一定的问题,我们前面的条件是设置在空间充足的情况下,如果空间不足的话,我们该怎么办呢?
当然是扩容啦!!!
所以我们再写一个检查空间是否充足的函数,如果不足顺便扩容。
那么,既然说到扩容,我们应该怎样扩容呢?
我这里有三种扩容方式:
1.一次扩容一个空间
2.一次扩容多个大小的空间
3.成倍的增加空间(1.5倍,2倍)
这里我推荐第三种方法。
理由:
第一种一次扩容一个空间,好处是不会造成空间的浪费,缺点是如果我们输入大量数据时,它需要多次开辟,导致程序效率低下。
第二种一次开辟多个空间,有效解决了第一种导致程序小路低下的问题,但是,它也有相应的问题,我们不能确定一次开辟多大的空间合适,如果开辟小了,一样也会和第一种一样多次扩容,影响程序效率,但如果一下周四开辟空间过大,也会导致空间被浪费。
我们先定义函数:
void SLCheckCapacity(SL* ps)
接着判断是否需要扩容,然后扩容空间,但是由于我们初始化直接是NULL所以这里我再加上一个三目操作符,总体代码如下:
void SLCheckCapacity(SL* ps)
{if (ps->size == ps->capacity){int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));if (tmp == NULL) {perror("realloc fail!");exit(1);}//扩容成功ps->arr = tmp;ps->capacity = newCapacity;}
}
这里我设置了tmp变量是为了防止扩容失败。这里我选择的就是扩容原来的两倍。
接下来我们按照上面的思路把头插完善
void SLPushFront(SL* ps, SLDataType x)
{assert(ps);SLCheckCapacity(ps);for (int i = ps->size; i > 0; i--) //i = 1{ps->arr[i] = ps->arr[i - 1]; //ps->arr[1] = ps->arr[0]}ps->arr[0] = x;ps->size++;
}
3.尾插
做完了头插,我们可以来试试尾插,数组中尾插是神简单的,如图:

如果空间充足,我们可以直接再尾部插入我们的数据然后吧size++,不够的话先扩容然后再执行
void SLPushBack(SL * ps, SLDataType x)
{assert(ps);SLCheckCapacity(ps);ps->arr[ps->size++] = x;
}
这样头插和尾插就完成了
4.头删
完成了插入那么我们还需要完成删除,删除相比较插入它有什么不同?删除不需要太在意空间。
现在我们先来完成头删。
在数组中我们怎么完成头删的呢?如图
我们一般是把每个数向前移动一位,数组有效长度-1,及size--;
代码示例:
void SLPopFront(SL* ps)
{assert(ps);assert(ps->size);for (int i = 0; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}
注意:我们要确保ps和ps->size不为NULL
5.尾删
这个操作实现起来其实非常简单,我们可以直接size--;
代码示例:
void SLPopBack(SL* ps)
{assert(ps);assert(ps->size); ps->size--;}
完成这些,那么我要上难度了,删除指定位置的值/插入指定位置的值
6.删除指定位置的值
具体思路,就是遍历去寻找所需数值,然后并将该数值之后的数据的下标前移,siza--如图:

代码示例:
void SLErase(SL* ps, int pos) {assert(ps);assert(pos >= 0 && pos < ps->size);//pos以后的数据往前挪动一位for (int i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];//ps->arr[i-2] = ps->arr[i-1];}ps->size--;
}
7.在指定位置插入值
思路,找到数值将该数值及其后的向后移动一位。size++
如图:

代码示例:
void SLInsert(SL* ps, int pos, SLDataType x) {assert(ps);assert(pos >= 0 && pos <= ps->size);SLCheckCapacity(ps);//pos及之后的数据往后挪动一位,pos空出来for (int i = ps->size; i > pos; i--){ps->arr[i] = ps->arr[i - 1]; //ps->arr[pos+1] = ps->arr[pos]}ps->arr[pos] = x;ps->size++;
}
注:这是插入,要检查空间是否足够
8.打印
完成这些我们可以来尝试打印我们的顺序表,类似打印数组。
代码示例:
void SLPrint(SL* ps)
{for (int i = 0; i < ps->size; i++){printf("%d ", ps->arr[i]);}printf("\n");
}
9.销毁顺序表
在我们之前讲过动态内存开辟,最后要再释放。
代码示例:
void SLDestroy(SL* ps)
{assert(ps);if (ps->arr) {free(ps->arr);}ps->arr = NULL;ps->size = ps->capacity = 0;
}
最后来展示程序代码:
#include"SeqList.h"
void SLInit(SL* ps)
{ps->arr = NULL;ps->size = ps->capacity = 0;
}
void SLDestroy(SL* ps)
{assert(ps);if (ps->arr) {free(ps->arr);}ps->arr = NULL;ps->size = ps->capacity = 0;
}
void SLCheckCapacity(SL* ps)
{if (ps->size == ps->capacity){int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));if (tmp == NULL) {perror("realloc fail!");exit(1);}//扩容成功ps->arr = tmp;ps->capacity = newCapacity;}
}
void SLPushBack(SL * ps, SLDataType x)
{assert(ps);SLCheckCapacity(ps);ps->arr[ps->size++] = x;
}
void SLPushFront(SL* ps, SLDataType x)
{assert(ps);SLCheckCapacity(ps);for (int i = ps->size; i > 0; i--) //i = 1{ps->arr[i] = ps->arr[i - 1]; //ps->arr[1] = ps->arr[0]}ps->arr[0] = x;ps->size++;
}
void SLPopBack(SL* ps)
{assert(ps);assert(ps->size); ps->size--;}
void SLPopFront(SL* ps)
{assert(ps);assert(ps->size);for (int i = 0; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}
void SLInsert(SL* ps, int pos, SLDataType 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+1] = ps->arr[pos]}ps->arr[pos] = x;ps->size++;
}
void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);for (int i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];}ps->size--;
}
void SLPrint(SL* ps)
{for (int i = 0; i < ps->size; i++){printf("%d ", ps->arr[i]);}printf("\n");
}
void SLDestroy(SL* ps)
{assert(ps);if (ps->arr) {free(ps->arr);}ps->arr = NULL;ps->size = ps->capacity = 0;
}
//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x) {assert(ps);assert(pos >= 0 && pos <= ps->size);SLCheckCapacity(ps);//pos及之后的数据往后挪动一位,pos空出来for (int i = ps->size; i > pos; i--){ps->arr[i] = ps->arr[i - 1]; //ps->arr[pos+1] = ps->arr[pos]}ps->arr[pos] = x;ps->size++;
}
//删除指定位置数据
void SLErase(SL* ps, int pos) {assert(ps);assert(pos >= 0 && pos < ps->size);//pos以后的数据往前挪动一位for (int i = pos; i < ps->size - 1; i++){ps->arr[i] = ps->arr[i + 1];//ps->arr[i-2] = ps->arr[i-1];}ps->size--;
}
这样一个循序表完成了,你可以用设计的函数来进行操作。
相关文章:
[数据结构]顺序表
1、顺序表的概念及结构 1.1 线性表 线性表( linear list )是n个具有相同特性的数据元素的有限序列。 线性表是⼀种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结构&#…...
北斗卫星为野外科考人员提供安全保障
北斗卫星为野外科考人员提供安全保障 自第二次青藏高原综合科学考察研究启动以来,青海不断提升科考服务保障能力,推动科考全程信息化,有效促进科考成果转化。 为保障科考人员的人身安全,青海省青藏科学考察服务中心开发了基于北…...
Linux的一些快捷键(hot keyboard)
Ctrl Alt t:打开bash(就是命令框窗口) Ctrl Alt F3~F6:打开tty终端(纯命令行终端,每个Linux发行版不相同,我的是Ubuntu20版) Alt F4:关闭当前窗口(Windo…...
Charles将证书安装到系统的方法(adb)
基本情况参考此帖:Charles 安卓抓包 unknown 和证书无效的解决方案(无需改代码)_client ssl handshake failed: an unknown issue occu-CSDN博客 此解决方案仅适用于已root设备默认已经在电脑上安装并配置了Charles,安卓手机也下载…...
git 常用指令 (先收藏再说)
Git Git是一种分布式版本控制系统,用于记录一个或若干个文件内容的变化,以便查阅和回溯。 它的工作原理可以概括为以下几点: 工作区(Workspace):这是你在电脑上看到的目录,工作区是你用来修改文…...
2024问题汇总
2024问题汇总 Linux1.df-h / df -i 命令2.为多网卡Linux云服务器配置策略路由 Windows1.快速进入控制面板 网络连接指令 Linux 1.df-h / df -i 命令 df -h / df -i 都表示查看磁盘空间使用信息 如果遇到磁盘快满的情况,用这两个命令区别如下 df -h 是去删除比较大 …...
爬虫(学习笔记)
python爬虫 一、Python基础回顾变量类型其他操作面向对象编程 二、爬虫流程HTTP协议HTML爬虫demo01爬虫demo02 学习资料 Python爬虫 爬虫实战案例 AI学堂爬虫教学 一、Python基础回顾 变量类型 可变类型:可以进行添加、修改、删除 (列表、字典…&#x…...
让业务满意的性能测试报告模板应该是怎样的?
前言 先前在北京出差,和同事聊到了一个关于流量网关如何进行性能验证的需求,当时专门与同事进行了一番讨论,后面写了一篇相关文章。 结果没过多久同事找到我,希望我帮他们写一份给到业务团队的性能测试报告,原因是业…...
高防IP如何保护服务器
首先我们要知道什么是高防IP~ 高防IP是指高防机房所提供的ip段,主要是针对互联网服务器遭受大流量DDoS攻击时进行的保护服务。高防IP是目前最常用的一种防御DDoS攻击的手段,用户可以通过配置DDoS高防IP,将攻击流量引流到高防IP,防…...
C++提高编程——STL:string容器、vector容器
本专栏记录C学习过程包括C基础以及数据结构和算法,其中第一部分计划时间一个月,主要跟着黑马视频教程,学习路线如下,不定时更新,欢迎关注。 当前章节处于: ---------第1阶段-C基础入门 ---------第2阶段实战…...
three.js从入门到精通系列教程004 - three.js透视相机(PerspectiveCamera)滚动浏览全景大图
<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>three.js从入门到精通系列教程004 - three.js透视相机(PerspectiveCamera)滚动浏览全景大图</title><script src"js/three.js"&g…...
Gradle 笔记
Gradle依赖管理(基于Kotlin DSL) **注意:**如果不是工作原因或是编写安卓项目必须要用Gradle,建议学习Maven即可,Gradle的学习成本相比Maven高很多,而且学了有没有用还是另一回事,所以ÿ…...
flume案例
在构建数仓时,经常会用到flume接收日志数据,通常涉及到的组件为kafka,hdfs等。下面以一个flume接收指定topic数据,并存入hdfs的案例,大致了解下flume相关使用规则。 版本:1.9 Source Kafka Source就是一…...
信用评价研究MATLAB仿真代码
信用评价是各种店铺卖家分析买家信用行为的重要内容, 本文给出随机仿真代码模拟实际交易过程的信用评价. 主要研究内容有: (1)研究最大交易额和信用度的关系 (2)研究买家不评价率对信用度影响 (3)研究交易次数对信用度影响 MATLAB程序如下: 主程序main.m %% clc;close a…...
网络安全产品之认识防毒墙
在互联网发展的初期,网络结构相对简单,病毒通常利用操作系统和软件程序的漏洞发起攻击,厂商们针对这些漏洞发布补丁程序。然而,并不是所有终端都能及时更新这些补丁,随着网络安全威胁的不断升级和互联网的普及…...
android 防抖工具类,经纬度检查工具类
一:点击事件防抖工具类: public abstract class ThrottleClickListener implements View.OnClickListener {private long clickLastTimeKey 0;private final long thresholdMillis 500;//millisecondsOverridepublic void onClick(View v) {long curr…...
PgSQL - 17新特性 - 块级别增量备份
PgSQL - 17新特性 - 块级别增量备份 PgSQL可通过pg_basebackup进行全量备份。在构建复制关系时,创建备机时需要通过pg_basebackup全量拉取一个备份,形成一个mirror。但很多场景下,我们往往不需要进行全量备份/恢复,数据量特别大的…...
Vue3setup()的非语法糖和语法糖的用法
1、setup()的语法糖的用法 script标签上写setup属性,不需要export default {} setup() 都可以省 创建每个属性或方法时也不需要return 导入某个组件时也不需要注册 <script setup > // script标签上写setup属性,不需要export default {} set…...
HTTP状态信息
1xx: 信息 消息:描述:100 Continue服务器仅接收到部分请求,但是一旦服务器并没有拒绝该请求,客户端应该继续发送其余的请求。101 Switching Protocols服务器转换协议:服务器将遵从客户的请求转换到另外一种协议。 2xx: 成功 消息:描述:200…...
CSS之边框样式
让我为大家介绍一下边框样式吧!如果大家想更进一步了解边框的使用,可以阅读这一篇文章:CSS边框border 属性描述none没有边框,即忽略所有边框的宽度(默认值)solid边框为单实线dashed边框为虚线dotted边框为点线double边框为双实线 代码演示&…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...
FastAPI 教程:从入门到实践
FastAPI 是一个现代、快速(高性能)的 Web 框架,用于构建 API,支持 Python 3.6。它基于标准 Python 类型提示,易于学习且功能强大。以下是一个完整的 FastAPI 入门教程,涵盖从环境搭建到创建并运行一个简单的…...
【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
Bean 作用域有哪些?如何答出技术深度?
导语: Spring 面试绕不开 Bean 的作用域问题,这是面试官考察候选人对 Spring 框架理解深度的常见方式。本文将围绕“Spring 中的 Bean 作用域”展开,结合典型面试题及实战场景,帮你厘清重点,打破模板式回答,…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
