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

【编织时空一:探究顺序表与链表的数据之旅】

本章重点

  1. 线性表

  2. 顺序表

  3. 顺序表OJ题

1.线性表

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

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

2.顺序表

        顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。 顺序表中的元素在内存中是相邻存储的,每个元素都有一个对应的索引来标识其在顺序表中的位置。顺序表支持随机访问,可以通过索引直接访问任意位置的元素。

        顺序表一般可以分为:

1. 静态顺序表:使用定长数组存储元素。

 静态顺序表的缺点:

  1. 固定大小: 静态顺序表的大小在创建时被固定下来,无法动态地扩展或缩小。这意味着一旦初始化了静态顺序表,其容量就无法改变。如果需要存储的元素数量超过初始分配的容量,可能需要重新分配更大的空间并手动进行数据迁移。

  2. 内存浪费: 如果静态顺序表的容量设置过大,但实际存储的元素数量较少,会导致内存浪费。因为未使用的部分空间也会被保留,占用了额外的内存。

  3. 不灵活: 由于容量固定,静态顺序表可能无法适应动态变化的数据需求。当需要的容量超过初始设置时,可能需要重新设计或重写代码。

  4. 初始化成本: 静态顺序表在初始化时需要分配固定大小的内存空间,而如果无法预估元素的最终数量,就需要进行适当的空间规划,这可能增加设计和开发的成本。

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

3.顺序表接口实现 

typedef int SLDataType;
// 顺序表的动态存储
typedef struct SeqList
{SLDataType* a;  // 指向动态开辟的数组int size;       // 有效数据个数int capicity;   // 容量空间的大小
}SeqList;// 基本增删查改接口
// 
// 顺序表初始化
void SeqListInit(SeqList * s);
// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* s);
// 顺序表尾插
void SeqListPushBack(SeqList* s, SLDataType x);
// 顺序表尾删
void SeqListPopBack(SeqList* s);
// 顺序表头插
void SeqListPushFront(SeqList* s, SLDataType x);
// 顺序表头删
void SeqListPopFront(SeqList* s);
// 顺序表查找
int SeqListFind(SeqList* s, SLDataType x);
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* s, size_t pos, SLDataType x);
// 顺序表删除pos位置的值
void SeqListErase(SeqList* s, size_t pos);
// 顺序表销毁
void SeqListDestory(SeqList* s);
// 顺序表打印
void SeqListPrint(SeqList* s);

顺序表初始化:void SeqListInit(SeqList * s);

        代码中存在一些问题,主要是关于C语言中函数参数传递方式的错误理解。C语言中的参数传递是值传递,意味着函数接收的是参数的副本,而不是原始的数据。因此,当你在 SeqListInit 函数中修改 s 的值时,实际上只是修改了传递进来的副本,而不会影响原始的 s。为了解决这个问题,需要通过指针传递来修改原始数据。

// 顺序表初始化
void SeqListInit(SeqList* s)
{s->a = NULL;s->size = 0;s->capicity = 0;
}

但是,我们需要在初始的时候就开辟一些空间,这样更方便数据存储,不用一上来就扩容。

// 顺序表初始化
void SeqListInit(SeqList* s)
{s->a = (SeqList*)malloc(sizeof(SLDataType) * 4);if (s->a == NULL){perror("malloc");//return;只是该函数退出,程序依然运行exit(-1);//程序退出为-1}s->size = 0;s->capicity = 4;
}

        malloc函数:malloc函数的返回值是void *,使用malloc函数要在返回的时候转化为我们需要的类型。malloc(sizeof(SLDataType) * 4)这代表的是申请了4个SLDataType类型大小的空间。        

        malloc函数的使用要引头文件#include<stdlib.h>。
        分配成功则返回指向被分配内存的指针,分配失败则返回空指针NULL。

检查空间,如果满了,进行增容:void CheckCapacity(SeqList* s);

// 检查空间,如果满了,进行增容
void CheckCapacity(SeqList* s)
{//满了需要扩容if (s->size == s->capicity){//realloc,第二个参数是新空间的大小,不是要扩多少SLDataType* temp = (SLDataType*)realloc(s->a, s->capicity * 2 * sizeof(SLDataType));//扩容2倍if (temp == NULL){perror("realloc");exit(-1);}s->a = temp;s->capicity *= 2;}
}

        realloc函数:realloc函数的返回值是void *,使用realloc函数要在返回的时候转化为我们需要的类型。realloc(s->a, s->capicity * 2 * sizeof(SLDataType))这代表的是申请了s->capicity * 2 个SLDataTypet型大小的空间。 我这里是扩充2倍空间。同时realloc函数,第二个参数是新空间的大小,不是要扩多少 。    

        realloc函数的使用要引头文件#include<stdlib.h>。
        分配成功则返回指向被分配内存的指针,分配失败则返回空指针NULL。

顺序表尾插:void SeqListPushBack(SeqList* s, SLDataType x);

// 顺序表尾插
void SeqListPushBack(SeqList* s, SLDataType x)
{CheckCapacity(s);s->a[s->size] = x;//尾插数字s->size++;//尾插后有效数字+1
}


顺序表尾删:void SeqListPopBack(SeqList* s);

// 顺序表尾删
void SeqListPopBack(SeqList* s)
{s->a[s->size - 1] = 0;s->size--;
}

这样写有一个问题,万一要删除的数字就是0,你还把size-1的位置设置为0,就没有意义了,我们发现只用将size--就行,有效数字就会少一个,打印数据自然会少一个,下次再尾插原本的数据就会被覆盖,原数字也自然就被删除了。

// 顺序表尾删
void SeqListPopBack(SeqList* s)
{//s->a[s->size - 1] = 0;s->size--;
}

这样写是不是还有问题,假设删掉的数字比原本数字多怎么办?程序直接崩了,这样会出现越界访问的问题

// 顺序表尾删
void SeqListPopBack(SeqList* s)
{//方法一:if(s->size == 0)//保证不会被越界{return;}//s->a[s->size - 1] = 0;s->size--;//方法二:assert(s->size > 0);//s->a[s->size - 1] = 0;s->size--;
}

顺序表头插:void SeqListPushFront(SeqList* s, SLDataType x);

// 顺序表头插
void SeqListPushFront(SeqList* s, SLDataType x)
{CheckCapacity(s);//挪动数据int end = s->size - 1;//最后一个数据while (end >= 0){s->a[end + 1] = s->a[end];end--;}s->a[0] = x;s->size++;
}


顺序表头删:void SeqListPopFront(SeqList* s);

// 顺序表头删
void SeqListPopFront(SeqList* s)
{assert(s->size > 0);//防止越界int begin = 0;while (begin < s->size - 1){s->a[begin] = s->a[begin + 1];begin++;}s->size--;
}

顺序表查找:int SeqListFind(SeqList* s, SLDataType x);

顺序表有顺序存取的功能,因此按位查找元素可以直接通过数组下标定位取得。

// 顺序表查找
int SeqListFind(SeqList* s, SLDataType x)
{for (int i = 0; i < s->size; i++){if (s->a[i] == x)return i;}return -1;
}


顺序表在pos位置插入x:void SeqListInsert(SeqList* s, size_t pos, SLDataType x);

        顺序表的元素插入和插队是一个意思的。想象一下,有一个人要插队,他要插到第3个位置去,那么他前面的两个人不用动,而他后面的人都得动。具体步骤是:最后面的那个人后退一个位置,倒数第二个人后退到原来最后一个人的位置,这样子后面的每个人依次后退,最后就空出来了一个位置,这个人就插队进去了。顺序表也是这么插入的。在插入操作完成后表长+1(多了一个人)。

元素插入有一些要求:

  1. 元素下标是否越界(有没有插队到奇怪的位置)
  2. 顺序表存储空间是否满了(有没有位置让你插队)
// 顺序表在pos位置插入x
void SeqListInsert(SeqList* s, size_t pos, SLDataType x)
{//检查pos是否合法assert(pos >= 0 && pos <= s->size);//检查是否需要扩容CheckCapacity(s);int end = s->size - 1;while (end >= pos){s->a[end + 1] = s->a[end];end--;}s->a[pos] = x;s->size++;
}


顺序表删除pos位置的值:void SeqListErase(SeqList* s, size_t pos);

        删除和插入的操作类型,这里借用插队的例子说明。一群人在排队,有一个人有事临时走了,那么这个人的位置就空出来了,后面的人就一个个往前一步,补上这个空位。在删除操作完成后表长-1(少了一个人)。

元素删除有一些要求:

  1. 元素下标是否越界(走的人是不是这个排队里面的人)
  2. 顺序表存储空间是否为空(有没有人可以走)
// 顺序表删除pos位置的值
void SeqListErase(SeqList* s, size_t pos)
{//检查pos是否合法assert(pos >= 0 && pos < s->size);int begin = pos;while (begin < s->size - 1){s->a[begin] = s->a[begin + 1];begin++;}s->size--;
}


顺序表销毁:void SeqListDestory(SeqList* s);

        顺序表初始化的时候是用malloc函数向系统申请的空间,malloc函数申请的空间是在内存的堆区,堆区的空间不会被系统自动回收,还需要用free函数释放空间。与malloc一样,要引头文件#include<stdlib.h>。

// 顺序表销毁
void SeqListDestory(SeqList* s)
{free(s->a);//释放开辟的空间s->a = NULL;s->size = 0;s->capicity = 0;
}

顺序表打印:void SeqListPrint(SeqList* s);

// 顺序表打印
void SeqListPrint(SeqList* s)
{for (int i = 0; i < s->size; i++){printf("%d ", s->a[i]);}printf("\n");
}

修改顺序表pos位置的值

// 修改顺序表pos位置的值
void SeqListModify(SeqList* s, size_t pos, SLDataType x)
{assert(pos >= 0 && pos < s->size);//修改pos位置的值s->a[pos] = x;
}

3.顺序表OJ题

1. 原地移除数组中所有的元素val,OJ链接:

https://leetcode.cn/problems/remove-element/

思路一:暴力解法

这个题目暴力的解法就是两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。

删除过程如下:

int removeElement(int* nums, int numsSize, int val) 
{int size = numsSize;for (int i = 0; i < size; i++) {if (nums[i] == val) { // 发现需要移除的元素,就将数组集体向前移动一位for (int j = i + 1; j < size; j++) {nums[j - 1] = nums[j];}i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位size--; // 此时数组的大小-1}}return size;
}
  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1)

思路二:双指针法(快慢指针法): 通过一个快指针和慢指针在一个whiler循环下完成工作。

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置

删除过程如下:

int removeElement(int* nums, int numsSize, int val)
{int fastindex = 0;int slowindex = 0;while (fastindex < numsSize){if (nums[fastindex] != val){nums[slowindex++] = nums[fastindex++];//赋值}else{fastindex++;//发现需要移除的元素,就将指针向后移动一位}}return slowindex;
}
  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

2. 删除排序数组中的重复项,OJ链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-array/

3. 合并两个有序数组,OJ链接:https://leetcode.cn/problems/merge-sorted-array/

void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) 
{int end1 = m;int end2 = n;int end = m + n;while (end1 >= 0 && end2 >= 0){if (nums1[end1] < nums2[end2])nums1[end--] = nums2[end2--];elsenums1[end--] = nums1[end1--];}while (end2 >= 0)nums1[end--] = nums2[end2--];
}

 本节结束啦!

相关文章:

【编织时空一:探究顺序表与链表的数据之旅】

本章重点 线性表 顺序表 顺序表OJ题 1.线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串... 线性表在逻辑上是线性结…...

Tesseract用OpenCV进行文本检测

我没有混日子&#xff0c;只是辛苦的时候没人看到罢了 一、什么是Tesseract Tesseract是一个开源的OCR&#xff08;Optical Character Recognition&#xff09;引擎&#xff0c;OCR是一种技术&#xff0c;它可以识别和解析图像中的文本内容&#xff0c;使计算机能够理解并处理…...

XLua案例学习

下载 xlua 之后把 asset 文件中的全部文件粘贴到项目文件Asset文件下&#xff0c;将tool粘贴到 asset 同级目录下 然后把 HOTFIX_ENABLE 宏打开 之后 编辑 lua 脚本 更改源代码之后先 Generate Code 然后 HotFix inject in Editor 开发过程&#xff1a; 首先开发业务…...

Linux:Shell编程之免交互

目录 绪论 1、here Document免交互 1.1 格式 1.2 cat结合免交互实现重定向输出到指定文件 1.3 变量替换 2、Expect免交互 2.1 三种写法 3、免交互实现普通用户切换root 3.1 send_user 4、接收参数 5、嵌入执行模式 6、ssh远程登录 绪论 免交互&#xff1a;不需要人…...

最强自动化测试框架Playwright(18)- 执行js脚本

page.evaluate&#xff08;&#xff09; API 可以在网页上下文中运行 JavaScript 函数&#xff0c;并将结果带回 Playwright 环境。 href page.evaluate(() > document.location.href) 如果结果是 Promise 或函数是异步的&#xff0c;则计算将自动等待&#xff0c;直到解析…...

阿里云云主机_ECS云服务器_轻量_GPU_虚拟主机详解

阿里云云主机分为云虚拟主机、云服务器ECS、轻量应用服务器、GPU云服务器、弹性裸金属服务器、专有宿主机、FPGA云服务器、高性能计算E-HPC、无影云电脑等&#xff0c;阿里云百科来详细说下阿里云云主机详解&#xff1a; 目录 阿里云云主机 云服务器ECS 轻量应用服务器 云…...

[QT编程系列-41]:Qt QML与Qt widget 深入比较,快速了解它们的区别和应用场合

目录 1. Qt QML与Qt widget之争 1.1 出现顺序 1.2 性能比较 1.3 应用应用领域 1.4 发展趋势 1.5 QT Creator兼容上述两种设计风格 2. 界面描述方式的差别 3. QML和Widgets之间的一些比较 4. 选择QML和Widgets之间的Qt技术时&#xff0c;可以考虑以下几个因素&#xff…...

springboot 使用zookeeper实现分布式锁

一.添加ZooKeeper依赖&#xff1a;在pom.xml文件中添加ZooKeeper客户端的依赖项。例如&#xff0c;可以使用Apache Curator作为ZooKeeper客户端库&#xff1a; <dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</…...

ViewUI表格Table嵌套From表单-动态校验数据合法性的解决方法

项目场景&#xff1a; 项目需求&#xff1a;在表格中实现动态加减数据&#xff0c;并且每行表格内的输入框&#xff0c;都要动态校验数据&#xff0c;校验不通过&#xff0c;不让提交数据&#xff0c;并且由于表格内部空间较小&#xff0c;我仅保留红边框提示&#xff0c;文字…...

服务器安装Tomcat

下载Tomcat 下载地址在这&#xff1a; Tomcat官网 下载完成以后把压缩包上传到服务器中&#xff08;我传到了www/java&#xff09;,进行解压(解压到)&#xff0c;如果没有进行指定解压到哪里&#xff0c;默认是到root文件夹中 tar -zxvf /www/java/apache-tomcat-9.0.103.tar.…...

【Apollo】自动驾驶的平台背景,平台介绍

作者简介&#xff1a; 辭七七&#xff0c;目前大一&#xff0c;正在学习C/C&#xff0c;Java&#xff0c;Python等 作者主页&#xff1a; 七七的个人主页 文章收录专栏&#xff1a; 七七的闲谈 欢迎大家点赞 &#x1f44d; 收藏 ⭐ 加关注哦&#xff01;&#x1f496;&#x1f…...

docker 安装与配置

一、 环境准备 IP主机名操作系统版本docker版本192.168.168.128master01CentOS Linux release 7.9.2009 (Core)docker-20.10.15.tgz 二、安装 # 安装包获取 cd /root wget -c https://download.docker.com/linux/static/stable/x86_64/docker-20.10.15.tgz [rootmaster01 ~]…...

Titanic--细节记录三

目录 image sklearn模型算法选择路径图 留出法划分数据集 ‘留出’的含义 基本步骤和解释 具体例子 创造一个数据集 留出法划分 预测结果可视化 分层抽样 设置方法 划分数据集的常用方法 train_test_split 什么情况下切割数据集的时候不用进行随机选取 逻辑回归…...

k8s-----集群调度

目录 一&#xff1a;调度约束 二&#xff1a;Pod 启动创建过程 三&#xff1a;k8s调度过程 1、Predicate 有一系列的常见的算法 2、常见优先级选项 3、指定调度节点 &#xff08;1&#xff09;nodeName指定 &#xff08;2&#xff09;nodeSelector指定 四&#xff1a;亲和…...

01-Spark环境部署

1 Spark的部署方式介绍 ​ Spark部署模式分为Local模式&#xff08;本地模式&#xff09;和集群模式&#xff08;集群模式又分为Standalone模式、Yarn模式和Mesos模式&#xff09; 1.1 Local模式 Local模式常用于本地开发程序与测试&#xff0c;如在idea中 1.2 Standalone模…...

HOT86-单词拆分

leetcode原题链接&#xff1a;单词拆分 题目描述 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。注意&#xff1a;不要求字典中出现的单词全部都使用&#xff0c;并且字典中的单词可以重复使用。 示例 1&#xff1a…...

开源数据集分类汇总(医学,卫星,分割,分类,人脸,农业,姿势等)

本文汇总了医学图像、卫星图像、语义分割、自动驾驶、图像分类、人脸、农业、打架识别等多个方向的数据集资源&#xff0c;均附有下载链接。 该文章仅用于学习记录&#xff0c;禁止商业使用&#xff01; 1.医学图像 疟疾细胞图像数据集 下载链接&#xff1a;http://suo.nz/2V…...

Linux:Firewalld防火墙

目录 绪论 1、firewalld配置模式 2、预定义服务&#xff1a;系统自带 3端口管理 绪论 firewalld 防火墙&#xff0c;包过滤防火墙&#xff0c;工作在网络层&#xff0c;centos7自带的默认的防火墙 作用是为了取代iptables 1、firewalld配置模式 运行时配置 永久配置 i…...

mysql死锁;锁表排查

概述 有时候提前终止了navicat执行线程&#xff0c;但是实际mysql还在执行这个线程&#xff0c; 需要通过mysql本身去终止. mysql:8.0 三板斧第一斧 捞点网上线程现成的执行命令 1.查询是否锁表 show OPEN TABLES where In_use > 0;2.查询进程&#xff08;如果您有SUP…...

YAMLException: java.nio.charset.MalformedInputException: Input length = 1

springboot项目启动的时候提示这个错误&#xff1a;YAMLException: java.nio.charset.MalformedInputException: Input length 1 根据异常信息提示&#xff0c;是YAML文件有问题。 原因是yml配置文件的编码有问题。 需要修改项目的编码格式&#xff0c;一般统一为UTF-8。 或…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

Java + Spring Boot + Mybatis 实现批量插入

在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法&#xff1a;使用 MyBatis 的 <foreach> 标签和批处理模式&#xff08;ExecutorType.BATCH&#xff09;。 方法一&#xff1a;使用 XML 的 <foreach> 标签&#xff…...