【数据结构】 顺序表
文章目录
- 1 线性表
- 2 顺序表
- 2.1 概念及结构
- 2.2 接口实现
- 2.3 数组相关面试题
- 2.4 顺序表的问题与思考
 
1 线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就是说是连续的一条直线。但是在物理结构上不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。

 
2 顺序表
那么今天我们首先来学习顺序表,然后再学习链表,有一个循序渐进的效果
2.1 概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表一般可以分为:
- 静态顺序表:使用定长数组存储元素。
这种顺序表空间固定,那么存储到一定数量时就不能存储,不太方便
- 动态顺序表:使用动态开辟的数组存储
动态开辟就很好解决了空间不够的问题。
2.2 接口实现
静态顺序表只适用于确定知道需要存多少数据的场景。
静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。
所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。
//那么我们先来实现接口函数#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
typedef int SLDataType;
#define INIT_CAPACITY 4typedef struct SeqList//顺序表的创建
{SLDataType* s;//作为动态数组来初始化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 SLSearch(SL* ps, SLDataType x);//寻找某个元素并且返回下标
写完接口函数时,就要实现函数了
注意:在写代码时,最好写完一个接口函数就要进行调试,这样找错误就很方便。
//首先是对顺序表的初始化
void SLInit(SL* ps)
{assert(ps);//进行断言,ps指向的对象不为空ps->s = (SLDataType*)malloc(sizeof(SLDataType) * INIT_CAPACITY);//malloc开辟空间时,后面要考虑开辟失败的情况,要进行检查if (ps->s == NULL){perror("malloc fail");return;}ps->size = 0;//初始化没有元素ps->capacity = INIT_CAPACITY;//进行初始化
}
//打印顺序表
void SLPrint(SL* ps)
{assert(ps);//如果是空的顺序表就不能打印int i = 0;for (i = 0; i < ps->size; i++){printf("%d ", ps->s[i]);}printf("\n");//打印完换行
}
//进行容量检查
void SLCheckCapacity(SL* ps)
{assert(ps);//判断为不为空顺序表if (ps->size == ps->capacity)//在进行尾部插入数据时要先判断空间够不够,不够要进行扩容{SLDataType* ptr =(SLDataType*)realloc(ps->s, sizeof(SLDataType) * ps->capacity * 2);//这里使用新的指针是因为如果开辟失败返回空指针,就不会影响到原来开辟的内存空间if (ptr == NULL){perror("realloc fail");return;}ps->s = ptr;//开辟成功将新开辟空间的指针赋给原来的指针ps->capacity *= 2;//因为空间扩大了两倍,那么容量也要扩大两倍}
}
//进行尾部插入数据
void SLPushBack(SL* ps, SLDataType x)
{assert(ps);//断言可以找到问题SLCheckCapacity(ps);//尾部插入要判断最后一个元素有没有空间,没有则开辟ps->s[ps->size] = x;//将数据赋给最后一个元素ps->size++;//同时将元素个数加一//SLInsert(ps, ps->size, x);//这个函数先不用管,后面会讲
}
//进行头部插入数据
void SLPushFront(SL* ps, SLDataType x)
{assert(ps);//判断为不为空SLCheckCapacity(ps);//判断容量够不够for (int i = ps->size - 1; i >= 0; i--){ps->s[i + 1] = ps->s[i];//将所有的数往后移一位}ps->size++;//元素要加一ps->s[0] = x;//进行赋值//SLInsert(ps, 0, x);//后面会讲
}
//进行尾部删除
void SLPopBack(SL* ps)
{assert(ps);//判断不为空assert(ps->size > 0);//判断顺序表中有没有元素ps->size--;//直接删除一个元素
}
//进行头部删除
void SLPopFront(SL* ps)
{assert(ps);//判读为不为空assert(ps->size > 0);//当这个数组是空的,size就为负数了//那么头部删除就可以进行覆盖,可以用memmove函数;也可以进行一个一个覆盖int begin = 0;for (begin = 1; begin <= ps->size - 1; begin++){ps->s[begin - 1] = ps->s[begin];//后一个将前一个进行覆盖}ps->size--;//让元素减一
}
//进行插入数据
void SLInsert(SL* ps, int pos, SLDataType x)//这个插入包括了头插和尾插,所以可以进行复用
{assert(ps);//判断为不为空assert(pos >= 0 && pos <= ps->size);//判断指定下标要合法,等于0就是要头插,等于ps->size就是要尾插SLCheckCapacity(ps);//检查容量是否充足int end = ps->size - 1;while (end >= pos){ps->s[end + 1] = ps->s[end];end--;//往后一个一个赋值}ps->s[pos] = x;//最后在pos位置赋值为xps->size++;//元素个数加一
}
//进行删除元素
void SLErase(SL* ps, int pos)
{assert(ps);//判断为不为空assert(pos >= 0 && pos < ps->size);//判断位置要合法int begin = pos + 1;while (begin < ps->size){ps->s[begin - 1] = ps->s[begin];++begin;//一个一个往前覆盖}ps->size--;//元素要减一
}
//进行元素的查找,找到了则返回下标,没找到则返回-1
int SLSearch(SL* ps, SLDataType x)//返回元素下标,要有返回值
{assert(ps);//判断为不为空for (int i = 0; i < ps->size; i++){if (ps->s[i] == x)return i;//进行循环查找,找到了就返回下标}return -1;//循环结束代表没找到,返回-1表示没找到
}//最后进行顺序的销毁
void SLDestroy(SL* ps)//销毁顺序表时,要释放内存,并且将指针设为空
{assert(ps);//判断为不为空free(ps->s);//释放指针所指向的内存空间ps->s = NULL;//同时将指针置为空ps->size = ps->capacity = 0;//元素和容量置为0
}
注意:在进行传参数时,如果要改变所指向的内容,就要传地址过去,不要传值过去,切记!!!
2.3 数组相关面试题
顺序表的内容完成后,那么接下来就要写写题目来巩固能力了
- 原地移除数组中所有的元素val,要求时间复杂度为O(N),空间复杂度O(1)。
https://leetcode.cn/problems/remove-element/
//首先我们可以将元素覆盖的方式去写。
int removeElement(int* nums, int numsSize, int val) {int src = 0;//作为遍历数组的元素int dst = 0;//作为返回数组的新长度while (src < numsSize){if (nums[src] != val){nums[dst++] = nums[src];//如果不等于元素不相等,那么将dst加一,src也加一}src++;//如果相等,只有src加一,dst不加一,等下个元素进行覆盖}return dst;//最后返回数组的新长度
}//也可以这样写
int removeElement(int* nums, int numsSize, int val) {int src = 0;int dst = 0;while (src < numsSize){if (nums[src] != val){nums[dst++] = nums[src++];//上面的方式更加简洁,因为src哪种情况都要加一}else{src++;}}return dst;
}
//
- 删除排序数组中的重复项。
https://leetcode.cn/problems/remove-duplicates-from-sorted-array/
//这道题目和上一个思路差不多,每个数字之只能出现一次,返回数组的新长度
//我们使用快慢指针
int removeDuplicates(int* nums, int numsSize){int src = 1;//让src为1int dst = 0;while (src < numsSize){if (nums[dst] == nums[src]){src++;//两个数相等就src加1}else{nums[++dst] = nums[src++];//不相等就进行赋值}}return dst + 1;//最后返回dst+1
}//结合图片进行理解
//
- 合并两个有序数组
https://leetcode.cn/problems/merge-sorted-array/
//这里的非递减是可能递增也可能相等
//这里我们可以从头一个一个比较,小的放前面,大的放后面,但这样比较实在麻烦。换个角度,如果从后面开始放就会方便很多。
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){int end1 = m - 1;//作为最后一个元素比较int end2 = n - 1;int dst = m + n - 1;while (end1 >= 0 && end2 >= 0){if (nums2[end2] > nums1[end1]){nums1[dst--] = nums2[end2--];//如果大,那么num2放元素}else{nums1[dst--] = nums1[end1--];//如果小,那么num1放元素}}while (end2 >= 0)//这里判断end2,如果还有元素,依次放上去//不判断end1的原因是num1的元素就在num1中,不用进行移植{nums1[dst--] = nums2[end2--];}
}
//结合动态理解!(https://img-blog.csdnimg.cn/7a9667b48f7d40e48155cfb77ec0dd45.gif#pic_center)以上题目希望可以加深和理解顺序表
2.4 顺序表的问题与思考
问题:
- 中间/头部的插入删除,时间复杂度为O(n)
- 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
- 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们在再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
如何解决以上问题呢?那就要使用链表了!!!
这次我们学习了顺序表,下次学习链表,希望各位学习永无止境!!!o_O
晚风庭院落梅初。淡云来往越疏疏。–李清照
相关文章:
 
【数据结构】 顺序表
文章目录1 线性表2 顺序表2.1 概念及结构2.2 接口实现2.3 数组相关面试题2.4 顺序表的问题与思考1 线性表 线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序…...
Elasticsearch 集群规划- 单台机器核心数计算公式
在做集群规划的时候,到底需要给集群的每个节点多少个核心数?这个问题一直困扰了我很久。最近一段时间做千亿数据,PB存储量集群规划的时候,突然想明白了这件事,大致可以用一个公式来计算!我觉得这是一个非常…...
 
Tesla都使用什么编程语言?
作者 | 初光 出品 | 车端 备注 | 转载请阅读文中版权声明 知圈 | 进“汽车电子与AutoSAR开发”群,请加微“cloud2sunshine” 总目录链接>> AutoSAR入门和实战系列总目录 带着对更美好未来的愿景,特斯拉不仅成为有史以来最有价值的汽车公司&…...
 
1143. 最长公共子序列——【Leetcode每日刷题】
1143. 最长公共子序列 给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。 一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些…...
【并发基础】线程的通知与等待:obj.wait()、obj.notify()、obj.notifyAll()详解
目录 〇、先总结一下这三个方法带来的Java线程状态变化 一、obj.wait() 1.1 作用 1.2 使用前需要持有线程共享对象的锁 1.3 使用技巧 二、obj.notify(All)() 1.1 notify() 方法 1.1.1 调用notify()或notifyAll()不会释放线程的锁 1.2 notifyAll() 方法 1.3 使用技巧 三、使用实…...
 
css黏性定位-实现商城的分类滚动的标题吸附
传统的黏性定位是使用js通过计算高度来实现的,当元素滚动到一定位置时吸附在当前位置。下面我们通过css来实现黏性定位功能。 黏性定位 黏性定位目前主流的浏览器已经全部支持,顾名思义,黏性定位具有吸附的效果,其实它是positio…...
@Component和@bean注解在容器中创建实例区别
Component和Bean的区别 在Spring Boot中,Component注解和Bean注解都可以用于创建bean。它们的主要区别在于它们的作用范围和创建方式。 Component注解是一种通用的注解,可以用于标注任何类。被标注的类将被Spring容器自动扫描并创建为一个bean。这个bea…...
 
不写注释就是垃圾
最近Linux6.2出来了增加了很多新的东西,有看点的是,Linux确实要可以在Apple M1上面运行了,这应该是一个很大的新闻,如果有这么稳定的硬件支持,那对于Linux来说相当于又打下了一大片的江山。其中关于Linux6.2的特性罗列…...
深信服一面
1.C变量存储在哪里,生命周期是怎样的 2.静态成员变量和成员函数的特性,在哪里用过吗 3.new和delete是什么,和malloc和free对比有啥优势 4.new能不能重载,重载new有什么用 5.多态是怎么实现的,有什么优势和目的 6.…...
 
【C语言】深度理解指针(中)
前言✈上回说到,我们学习了一些与指针相关的数据类型,如指针数组,数组指针,函数指针等等,我们还学习了转移表的基本概念,学会了如何利用转移表来实现一个简易计算器。详情请点击传送门:【C语言】…...
步进电机运动八大算法
引导一种模块化(Module)设计思想,将传统步进电机的控制器(controller)、驱动器(Driver)、运动算法(Arithmetic)三合一。 对比国内外步进电机驱动原理和已有工作,结合各种硬件特性,改进或实现了可实际移植并用于步进电机控制八大算法。本产品…...
如果你持续大量的教坏ChatGPT,它确实会变坏
你输出的很多数据是经过人工标注吗,以确保可以正常对外展示出来,而不是有性别歧视、种族歧视或者其它意识形态为多数人所不认同的内容产生? 作为AI语言模型,我并不直接处理或输出任何数据,我的任务是通过对输入的自然语…...
 
opencv学习(二)图像阈值和平滑处理
图像阈值ret, dst cv2.threshold(src, thresh, maxval, type)src: 输入图,只能输入单通道图像,通常来说为灰度图dst: 输出图thresh: 阈值maxval: 当像素值超过了阈值(或者小于阈值,…...
 
【含源码】用python做游戏有多简单好玩
有很多同学问我还有其他什么小游戏吗,游戏是怎么做的,难不难。我就用两篇文章来介绍一下,如何使用Python做游戏。 兔子与灌 俄罗斯方块 休闲五子棋 走迷宫 推箱子 消消乐 超多小游戏玩转不停↓ 更多小游戏可以评论区讨论哦,喜欢…...
C++常用函数
std::sort std::sort 函数用于对数组或容器进行排序,可以按照默认的升序排序或指定比较函数进行排序。 语法如下: template <class RandomAccessIterator> void sort(RandomAccessIterator first, RandomAccessIterator last);template <clas…...
Android Framework基础到深入篇
Android Framework基础到深入篇 KernelSU Android上基于内核的Root方案 Android系统源码下载/编译篇...
 
【Go进阶训练营】聊一下go的gc原理
背景 正好周末时间,就打算梳理以下自己对go gc的理解。跳出语言层面来说,gc分为两种,一种是手动创建,手动销毁。另一种就是由自动分配自动销毁,前者就是c,c的代表,后者就是java,go。 而整个流程…...
英飞凌Tricore原理及应用介绍05_中断处理之中断路由(IR)模块详解
目录 1.概述1.1相关缩写2 TC3xx中IR特性介绍3.SRN(中断服务请求优先级)3.1 寄存器中的各Bit位讲解3.2 如何改变SRN配置4. 实际应用介绍4.1 如何利用SRC寄存器检查OS中断配置是否正确?1.概述 在Tricore架构中允许有多个中断源包括片上外设及外部中断世间产生的中断请求,以打…...
 
微搭问答002-移动端上传的文件如何在PC端下载
遇到一个问题,就是上传的图片,在手机上可以下载了,但在电脑上怎么下载到电脑 里,包括上传的文件 点击查看页面就可以吧,在企业工作台里 我做了查看页面,小程序可以,但H5和电脑页面不行 你创建一…...
 
初识JVM
目录 引言 JVM是什么? JVM和java有什么联系? JDK、JRE、JVM有什么区别 为什么学习JVM? JVM——从内存管理开始 运行时数据区域 分区讲解 堆 方法区 程序计数器 本地技术栈 虚拟机栈 对象的创建 指针碰撞: 空闲列表…...
 
工业安全零事故的智能守护者:一体化AI智能安防平台
前言: 通过AI视觉技术,为船厂提供全面的安全监控解决方案,涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面,能够实现对应负责人反馈机制,并最终实现数据的统计报表。提升船厂…...
 
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
 
Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...
音视频——I2S 协议详解
I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...
 
手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...

