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

【数据结构】 顺序表

文章目录

  • 1 线性表
    • 2 顺序表
    • 2.1 概念及结构
    • 2.2 接口实现
    • 2.3 数组相关面试题
    • 2.4 顺序表的问题与思考

1 线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…

线性表逻辑上是线性结构,也就是说是连续的一条直线。但是在物理结构不一定是连续的,线性表在物理上存储时,通常数组链式结构的形式存储。

在这里插入图片描述
在这里插入图片描述

2 顺序表

那么今天我们首先来学习顺序表,然后再学习链表,有一个循序渐进的效果

2.1 概念及结构

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

  1. 静态顺序表:使用定长数组存储元素。
    在这里插入图片描述
    这种顺序表空间固定,那么存储到一定数量时就不能存储,不太方便
  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 数组相关面试题

顺序表的内容完成后,那么接下来就要写写题目来巩固能力了

  1. 原地移除数组中所有的元素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://img-blog.csdnimg.cn/8c7e4339443448fc9930d677b4f59539.gif#pic_center)
  1. 删除排序数组中的重复项。
    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://img-blog.csdnimg.cn/0d82014700df493184df034d7e3de84d.gif#pic_center)
  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 顺序表的问题与思考

问题:

  1. 中间/头部的插入删除,时间复杂度为O(n)
  2. 增容需要申请新空间,拷贝数据,释放旧空间。会有不小的消耗。
  3. 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们在再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。

如何解决以上问题呢?那就要使用链表了!!!

这次我们学习了顺序表,下次学习链表,希望各位学习永无止境!!!o_O

晚风庭院落梅初。淡云来往越疏疏。–李清照

相关文章:

【数据结构】 顺序表

文章目录1 线性表2 顺序表2.1 概念及结构2.2 接口实现2.3 数组相关面试题2.4 顺序表的问题与思考1 线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序…...

Elasticsearch 集群规划- 单台机器核心数计算公式

在做集群规划的时候&#xff0c;到底需要给集群的每个节点多少个核心数&#xff1f;这个问题一直困扰了我很久。最近一段时间做千亿数据&#xff0c;PB存储量集群规划的时候&#xff0c;突然想明白了这件事&#xff0c;大致可以用一个公式来计算&#xff01;我觉得这是一个非常…...

Tesla都使用什么编程语言?

作者 | 初光 出品 | 车端 备注 | 转载请阅读文中版权声明 知圈 | 进“汽车电子与AutoSAR开发”群&#xff0c;请加微“cloud2sunshine” 总目录链接>> AutoSAR入门和实战系列总目录 带着对更美好未来的愿景&#xff0c;特斯拉不仅成为有史以来最有价值的汽车公司&…...

1143. 最长公共子序列——【Leetcode每日刷题】

1143. 最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些…...

【并发基础】线程的通知与等待: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通过计算高度来实现的&#xff0c;当元素滚动到一定位置时吸附在当前位置。下面我们通过css来实现黏性定位功能。 黏性定位 黏性定位目前主流的浏览器已经全部支持&#xff0c;顾名思义&#xff0c;黏性定位具有吸附的效果&#xff0c;其实它是positio…...

@Component和@bean注解在容器中创建实例区别

Component和Bean的区别 在Spring Boot中&#xff0c;Component注解和Bean注解都可以用于创建bean。它们的主要区别在于它们的作用范围和创建方式。 Component注解是一种通用的注解&#xff0c;可以用于标注任何类。被标注的类将被Spring容器自动扫描并创建为一个bean。这个bea…...

不写注释就是垃圾

最近Linux6.2出来了增加了很多新的东西&#xff0c;有看点的是&#xff0c;Linux确实要可以在Apple M1上面运行了&#xff0c;这应该是一个很大的新闻&#xff0c;如果有这么稳定的硬件支持&#xff0c;那对于Linux来说相当于又打下了一大片的江山。其中关于Linux6.2的特性罗列…...

深信服一面

1.C变量存储在哪里&#xff0c;生命周期是怎样的 2.静态成员变量和成员函数的特性&#xff0c;在哪里用过吗 3.new和delete是什么&#xff0c;和malloc和free对比有啥优势 4.new能不能重载&#xff0c;重载new有什么用 5.多态是怎么实现的&#xff0c;有什么优势和目的 6.…...

【C语言】深度理解指针(中)

前言✈上回说到&#xff0c;我们学习了一些与指针相关的数据类型&#xff0c;如指针数组&#xff0c;数组指针&#xff0c;函数指针等等&#xff0c;我们还学习了转移表的基本概念&#xff0c;学会了如何利用转移表来实现一个简易计算器。详情请点击传送门&#xff1a;【C语言】…...

步进电机运动八大算法

引导一种模块化(Module)设计思想&#xff0c;将传统步进电机的控制器(controller)、驱动器(Driver)、运动算法(Arithmetic)三合一。 对比国内外步进电机驱动原理和已有工作&#xff0c;结合各种硬件特性&#xff0c;改进或实现了可实际移植并用于步进电机控制八大算法。本产品…...

如果你持续大量的教坏ChatGPT,它确实会变坏

你输出的很多数据是经过人工标注吗&#xff0c;以确保可以正常对外展示出来&#xff0c;而不是有性别歧视、种族歧视或者其它意识形态为多数人所不认同的内容产生&#xff1f; 作为AI语言模型&#xff0c;我并不直接处理或输出任何数据&#xff0c;我的任务是通过对输入的自然语…...

opencv学习(二)图像阈值和平滑处理

图像阈值ret, dst cv2.threshold(src, thresh, maxval, type)src&#xff1a; 输入图&#xff0c;只能输入单通道图像&#xff0c;通常来说为灰度图dst&#xff1a; 输出图thresh&#xff1a; 阈值maxval&#xff1a; 当像素值超过了阈值&#xff08;或者小于阈值&#xff0c;…...

【含源码】用python做游戏有多简单好玩

有很多同学问我还有其他什么小游戏吗&#xff0c;游戏是怎么做的&#xff0c;难不难。我就用两篇文章来介绍一下&#xff0c;如何使用Python做游戏。 兔子与灌 俄罗斯方块 休闲五子棋 走迷宫 推箱子 消消乐 超多小游戏玩转不停↓ 更多小游戏可以评论区讨论哦&#xff0c;喜欢…...

C++常用函数

std::sort std::sort 函数用于对数组或容器进行排序&#xff0c;可以按照默认的升序排序或指定比较函数进行排序。 语法如下&#xff1a; template <class RandomAccessIterator> void sort(RandomAccessIterator first, RandomAccessIterator last);template <clas…...

Android Framework基础到深入篇

Android Framework基础到深入篇 KernelSU Android上基于内核的Root方案 Android系统源码下载/编译篇...

【Go进阶训练营】聊一下go的gc原理

背景 正好周末时间&#xff0c;就打算梳理以下自己对go gc的理解。跳出语言层面来说&#xff0c;gc分为两种&#xff0c;一种是手动创建&#xff0c;手动销毁。另一种就是由自动分配自动销毁&#xff0c;前者就是c,c的代表&#xff0c;后者就是java&#xff0c;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端下载

遇到一个问题&#xff0c;就是上传的图片&#xff0c;在手机上可以下载了&#xff0c;但在电脑上怎么下载到电脑 里&#xff0c;包括上传的文件 点击查看页面就可以吧&#xff0c;在企业工作台里 我做了查看页面&#xff0c;小程序可以&#xff0c;但H5和电脑页面不行 你创建一…...

初识JVM

目录 引言 JVM是什么&#xff1f; JVM和java有什么联系&#xff1f; JDK、JRE、JVM有什么区别 为什么学习JVM&#xff1f; JVM——从内存管理开始 运行时数据区域 分区讲解 堆 方法区 程序计数器 本地技术栈 虚拟机栈 对象的创建 指针碰撞&#xff1a; 空闲列表…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

基于数字孪生的水厂可视化平台建设:架构与实践

分享大纲&#xff1a; 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年&#xff0c;数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段&#xff0c;基于数字孪生的水厂可视化平台的…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

【JavaWeb】Docker项目部署

引言 之前学习了Linux操作系统的常见命令&#xff0c;在Linux上安装软件&#xff0c;以及如何在Linux上部署一个单体项目&#xff0c;大多数同学都会有相同的感受&#xff0c;那就是麻烦。 核心体现在三点&#xff1a; 命令太多了&#xff0c;记不住 软件安装包名字复杂&…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...

iview框架主题色的应用

1.下载 less要使用3.0.0以下的版本 npm install less2.7.3 npm install less-loader4.0.52./src/config/theme.js文件 module.exports {yellow: {theme-color: #FDCE04},blue: {theme-color: #547CE7} }在sass中使用theme配置的颜色主题&#xff0c;无需引入&#xff0c;直接可…...

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...

DBLP数据库是什么?

DBLP&#xff08;Digital Bibliography & Library Project&#xff09;Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高&#xff0c;数据库文献更新速度很快&#xff0c;很好地反映了国际计算机科学学术研…...