数据结构:顺序表详解
数据结构:顺序表详解
- 一、 线性表
- 二、 顺序表概念及结构
- 1. 静态顺序表:使用定长数组存储元素。
- 2. 动态顺序表:使用动态开辟的数组存储。
- 三、接口实现
- 1. 创建
- 2. 初始化
- 3. 扩容
- 4. 打印
- 5. 销毁
- 6. 尾插
- 7. 尾删
- 8. 头插
- 9. 头删
- 10. 插入任意位置数据
- 11. 删除任意位置数据
- 12. 查找
- 13. 修改
- 四:所有代码
一、 线性表
线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的。
线性表在物理上存储时,通常以数组和链式结构的形式.
二、 顺序表概念及结构
顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
顺序表一般可以分为:
1. 静态顺序表:使用定长数组存储元素。
2. 动态顺序表:使用动态开辟的数组存储。
三、接口实现
静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。
基本增删查改接口
//对数据管理 --- 增删查改
void SLInit(SL* ps); //初始化
void SLDestory(SL* ps); //释放
void SLPrint(SL* ps); //打印
void SLCheakCapacity(SL* ps); //检查容量 -- 扩容//头插头删 尾插尾删
void SLPushBack(SL* ps, SLDateType x); //尾插
void SLPopBack(SL* ps); //尾删
void SLPushFront(SL* ps, SLDateType x);//头插
void SLPopFront(SL* ps); //头删//返回下标,没找到返回-1
int SLFind(SL* ps, SLDateType); //查找元素,返回下标//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDateType x); //任意位置插入
//在pos位置删除x
void SLErase(SL* ps, int pos); //任意位置删除void SLModify(SL* ps, int pos, SLDateType x);//修改
1. 创建
由于在实际工程中,项目的实现都是采用模块化进行实现的。所以在此处博主也采用了模块化的方式进行实现。
#pragma once#include <stdio.h>
#include <assert.h>
#include <stdlib.h>//动态顺序表
typedef int SLDateType;
typedef struct SeqList
{SLDateType* a;//指向动态开辟的数组int size; //有效数据的个数int capacity;//容量空间的大小
}SL;
为了后续好修改类型数据,在此采用typedef将结构体类型struct SeqList 重新命名为SL。
在实际开发过程中,为了开发人员更好的输入数据,一般我们会将输入数据的数据类型重命名为SLDateType。(在本篇博客中,采用typedef将其数据类型int重命名为SLDateType)
2. 初始化
初始化时,理论上我们只需要开辟一个空间并置为空指针,并将结构体中的数据全部初始化为0即可。
但在实际开发过程中,我们一般会开辟一定大小的空间(本篇博客开4个空间,但具体开多少,各位可自行选择)。
代码实现:
void SLInit(SL* ps)
{assert(ps);ps->a = (SLDateType*)malloc(4 * sizeof(SLDateType));//开辟4个空间if (ps->a == NULL){perror("malloc");exit(-1);}//开辟成功ps->capacity = 4;//开辟多少空间,容量变为多少ps->size = 0;
}
3. 扩容
在后续我们插入数据时,已开辟容量可能已经无法满足需求了。这是就需要扩容。
那一次扩到多少呢?
在实际开发过程中我们一般是扩到原有空间的两倍。(当然你也可以开1000倍,只要后台空间足够大)
代码实现:
void SLCheakCapacity(SL* ps)
{assert(ps);if (ps->size == ps->capacity){//开辟空间X2SLDateType* tmp = (SLDateType*)realloc(ps->a, ps->capacity * sizeof(SLDateType) * 2);if (tmp == NULL){perror("realloc");exit(-1);}//开辟成功ps->a = tmp;ps->capacity *= 2;}
}
4. 打印
上述函数定义完成后,我们通常需要测试打印以下相关数据,来判断相关函数定义是否成功.
代码实现:
void SLPrint(SL* ps)
{assert(ps);for (int i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");
}
5. 销毁
由于上述空间是动态开辟的。所以当我们使用完时,要及时销毁,释放空间。
代码实现:
void SLDestory(SL* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0;
}
6. 尾插
尾插:在尾部插入一个数据。
但是在数据的尾部插入一个数据时,我们需要考虑一个问题:原有空间是否可以容纳新的数据,是否需要扩容。
所以我们在插入数据时,要先调用 SLCheakCapacity函数来检查是否需要扩容。
代码实现:
void SLPushBack(SL* ps, SLDateType x)
{assert(ps);SLCheakCapacity(ps);//检查是否需要扩容ps->a[ps->size] = x;ps->size++;
}
7. 尾删
尾删:删除尾部最后的一个元素。
但尾删同样也要考虑一个问题,空间中是否还有数据给我们删除。
所以在进行尾删时,我们可以采用assert函数断言空间中还有数据。
代码实现:
void SLPopBack(SL* ps)
{assert(ps);assert(ps->size >= 0);//断言空间中还有元素ps->size--;//下标减1
}
在删除数据时,我们不用将原有数据删除。只需要下标减1即可。
原因在于我们时根据下标来使用数据的,当下标减1后,尾部最后一个数据便无法进行访问。
Tips:
- 越界是不一定报错的,系统对越界的检查是一种设岗抽查。
- 以VS2022为例,微软公司在数据的开始前和结尾后的一小段空间设有一些特殊值。当程序结束或内存空间释放时,编译器就会检查这些值是否发生改变, 从而触发程序的保护机制。但如果这些值没有发生改变,即使发生越界访问,程序也不会报错。就像如果你酒驾,交警只在二环设关卡,但只要你不去二环,你就没事不会被发现。(每个编译器略有差异)
8. 头插
头插:在数据最开始地方插入数据。
同样,头插也要调用 SLCheakCapacity函数来检查空间是否足够,是否需要扩容。
代码实现:
void SLPushFront(SL* ps, SLDateType x)
{assert(ps);SLCheakCapacity(ps);//检查是否需要扩容//移动数据int i = ps->size-1;while (i >= 0){ps->a[i + 1] = ps->a[i];i--;}//移动数据完成,插入元素。同时有效个数加1ps->a[0] = x;ps->size++;
}
9. 头删
头删:删除数据最开始的元素。
思路和头插类似,只要下标从1开始,所有数据依次向前移动1位,再把有限个数减1即可。
同时头删也需要使用assert函数断言原有空间中还有数据可以删除。
代码实现:
void SLPopFront(SL* ps)
{assert(ps);assert(ps->size >= 0);//空间中还有数据可以删除//移动数据for (int begin = 1; begin < ps->size; begin++){ps->a[begin - 1] = ps->a[begin];}ps->size--;//有效个数减1
}
10. 插入任意位置数据
由于顺序表要求数据是连续存放的,所以我们只需要找到输入位置的下标pos即可。
【代码思路】:首先我们要检查输入下标是否合法,是有效下标;并检查是否有足够空间来容纳新数据,是否需要扩容。之后从输入的数据下标开始,所有元素向后移动一位,并把新数据插入到下标为pos处即可。
代码实现:
void SLInsert(SL* ps, int pos, SLDateType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);//检查下标是否合法SLCheakCapacity(ps); //检查空间是否足够//移动数据int end = ps->size - 1;while (end >= pos){ps->a[end + 1] = ps->a[end];end--;}ps->a[pos] = x;ps->size++;
}
11. 删除任意位置数据
【代码思路】:和插入任何位置数据思想类似。首先我们要检查输入下标pos是否合法。之后从输入下标开始,后一个元素拷贝到前一个元素空间。
代码实现:
void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);//下标是否合法//移动数据int begin = pos+1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;
}
12. 查找
【代码思路】:要查找某个元素。由于这里只是最简单的查找,我们直接暴力查找,遍历整个数组返回下标即可。更为复杂的数据查找,会有更高阶的数据结构来实现。
代码实现:
int SLFind(SL* ps, SLDateType x)
{assert(ps);for (int i = 0; i < ps->size; i++){if (x == ps->a[i])return i;}return -1;
}
13. 修改
【代码思路】: 要实现修改数据,我们只需要先判断输入下标是否合法。在将对应下标数据进行修改即可。
代码实现:
void SLModify(SL* ps, int pos, SLDateType x)
{assert(ps);assert(pos >= 0 && pos < ps->size);ps->a[pos] = x;
}
四:所有代码
SeqList.h源文件
#include <assert.h>
#include <stdlib.h>//动态顺序表
typedef int SLDateType;
typedef struct SeqList
{SLDateType* a;int size;int capacity;
}SL;//对数据管理 --- 增删查改
void SLInit(SL* ps);
void SLDestory(SL* ps);
void SLPrint(SL* ps);
void SLCheakCapacity(SL* ps);//头插头删 尾插尾删
void SLPushBack(SL* ps, SLDateType x);
void SLPopBack(SL* ps);
void SLPushFront(SL* ps, SLDateType x);
void SLPopFront(SL* ps);//返回下标,没找到返回-1
int SLFind(SL* ps, SLDateType);//在pos位置插入x
void SLInsert(SL* ps, int pos, SLDateType x);
//在pos位置删除x
void SLErase(SL* ps, int pos);void SLModify(SL* ps, int pos, SLDateType x);
SeqList.c头文件
#define _CRT_SECURE_NO_WARNINGS#include "SeqList.h"void SLInit(SL* ps)
{assert(ps);ps->a = (SLDateType*)malloc(4 * sizeof(SLDateType));if (ps->a == NULL){perror("malloc");exit(-1);}//开辟成功ps->capacity = 4;ps->size = 0;
}void SLDestory(SL* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0;
}void SLPrint(SL* ps)
{assert(ps);for (int i = 0; i < ps->size; i++){printf("%d ", ps->a[i]);}printf("\n");
}void SLCheakCapacity(SL* ps)
{assert(ps);if (ps->size == ps->capacity){SLDateType* tmp = (SLDateType*)realloc(ps->a, ps->capacity * sizeof(SLDateType) * 2);if (tmp == NULL){perror("realloc");exit(-1);}ps->a = tmp;ps->capacity *= 2;}
}void SLPushBack(SL* ps, SLDateType x)
{assert(ps);/*SLCheakCapacity(ps);ps->a[ps->size] = x;ps->size++;*/SLInsert(ps, ps->size, x);
}void SLPopBack(SL* ps)
{assert(ps);assert(ps->size >= 0);/*ps->size--;*/SLErase(ps, 0);
}void SLPushFront(SL* ps, SLDateType x)
{assert(ps);SLCheakCapacity(ps);//移动数据/*int i = ps->size-1;while (i >= 0){ps->a[i + 1] = ps->a[i];i--;}ps->a[0] = x;ps->size++;*/SLInsert(ps, 0, x);
}void SLPopFront(SL* ps)
{assert(ps);assert(ps->size >= 0);/*for (int begin = 1; begin < ps->size; begin++){ps->a[begin - 1] = ps->a[begin];}ps->size--;*/SLErase(ps, 0);
}int SLFind(SL* ps, SLDateType x)
{assert(ps);for (int i = 0; i < ps->size; i++){if (x == ps->a[i])return i;}return -1;
}void SLInsert(SL* ps, int pos, SLDateType x)
{assert(ps);assert(pos >= 0 && pos <= ps->size);SLCheakCapacity(ps);int end = ps->size - 1;while (end >= pos){ps->a[end + 1] = ps->a[end];end--;}ps->a[pos] = x;ps->size++;}void SLErase(SL* ps, int pos)
{assert(ps);assert(pos >= 0 && pos < ps->size);int begin = pos+1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;
}void SLModify(SL* ps, int pos, SLDateType x)
{assert(ps);assert(pos >= 0 && pos < ps->size);ps->a[pos] = x;
}
相关文章:

数据结构:顺序表详解
数据结构:顺序表详解 一、 线性表二、 顺序表概念及结构1. 静态顺序表:使用定长数组存储元素。2. 动态顺序表:使用动态开辟的数组存储。三、接口实现1. 创建2. 初始化3. 扩容4. 打印5. 销毁6. 尾插7. 尾删8. 头插9. 头删10. 插入任意位置数据…...

采集数据筛选-过滤不要数据或只保留指定数据
采集文章数据,有时候会遇到一些不需要采集的数据,或者只想采集一些特定的数据,可以使用简数采集器的内容过滤功能,对采集的数据进行筛选,只有符合的数据才采集保留。 可以用于过滤掉一些广告、专题、网站首页等无效数…...

RISC-V基础指令之shift移动指令slli、srli、srai、sll、srl、sra
RISC-V的shift指令是用于对一个寄存器或一个立即数进行位移运算,并将结果存放在另一个寄存器中的指令。位移运算就是把一个操作数的每一位向左或向右移动一定的位数,得到一个新的位。RISC-V的shift指令有以下几种: slli:左逻辑位…...

【沁恒蓝牙mesh】CH58x flash分区与数据存储管理
本文主要介绍了 沁恒蓝牙芯片 CH58x 的flash 分区与数据存储管理 📋 个人简介 💖 作者简介:大家好,我是喜欢记录零碎知识点的小菜鸟。😎📝 个人主页:欢迎访问我的 Ethernet_Comm 博客主页&…...

Ctfshow web入门 JWT篇 web345-web350 详细题解 全
CTFshow JWT web345 先看题目,提示admin。 抓个包看看看。 好吧我不装了,其实我知道是JWT。直接开做。 在jwt.io转换后,发现不存在第三部分的签证,也就不需要知道密钥。 全称是JSON Web Token。 通俗地说,JWT的本质…...

2023年国家留学基金委(CSC)青年骨干教师项目即将开始申报
国家留学基金委(以下简称CSC)的青年骨干教师出国研修项目(即高校合作项目),将于2023年9月10-25日进行网上报名及申请受理。知识人网小编特提醒申请者注意流程及政策,以防错过申报时间。 青年骨干教师项目&a…...

GC垃圾回收器【入门笔记】
GC:Garbage Collectors 垃圾回收器 C/C,手动回收内存;难调试、门槛高。忘记回收、多次回收等问题 Java、Golang等,有垃圾回收器:自动回收,技术门槛降低 一、如何定位垃圾? https://www.infoq.c…...

在 React 中渲染大型数据集的 3 种方法
随着 Web 应用程序变得越来越复杂,我们需要找到有效的方法来优化性能和渲染大型数据集。在 React 应用程序中处理大型数据集时,一次呈现所有数据可能会导致性能不佳和加载时间变慢。 虚拟化是一种通过一次仅呈现数据集的一部分来解决此问题的技术&#…...

uniapp iOS 消息推送扩展:后台/杀死app进程状态能语音播报
文章目录 引言I 前期准备1.1 配置扩展1.2 测试报文II iOS Extension(扩展)2.1 插件作者配置2.2 插件使用者配置see also引言 HBuilderX3.1.5+版本uni原生插件支持iOS Extension(扩展)。 消息推送离线语音播报插件获取方式: 公z号:iOS逆向: 离线包x10, 源码是x15。 实…...

批量创建可配置物料参数文件
启用可配置物料之后,每次创建新的物料需要通过CU41创建可配置物料,没找大批量创建的程序,所以SHDB录屏搞了一个代码。 前提:物料主数据初始化通过程序导入时,可配置物料参数文件已按照物料代码赋值。 效果…...

性能压力测试的重要性与实施方法
性能压力测试是在软件开发过程中评估系统在不同负载条件下的表现和稳定性的关键步骤。这种测试是为了确定系统在正常和峰值负载下的性能表现,以验证系统是否能够满足用户需求,同时发现潜在的性能问题并加以解决。 首先,性能压力测试对于确保系…...

HCIP入门静态实验
题目及要求 第一步:拓扑的搭建 第二步:路由、IP的配置 r1: <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sys r1 [r1]int loop [r1]int LoopBack 0 [r1-LoopBack0]ip add 192.168.1.65 27 [r1-LoopBack0]int loop 1 […...

Vue与js的融合,如何编写现代化的前端应用
随着Web应用的不断发展,前端开发已经成为了当今互联网行业中最为流行和重要的领域之一。而在前端开发中,JavaScript无疑是最为常用和基础的语言之一。而Vue.js作为一种轻量级的JavaScript框架,它的出现极大地简化了前端开发的过程,…...

Boost开发指南-3.10singleton_pool
singleton_pool singleton_pool与 pool的接口完全一致,可以分配简单数据类型(POD)的内存指针,但它是一个单件。 singleton_pool位于名字空间boost,为了使用singleton_pool组件,需要包含头文件<boost/p…...

腾讯云从业者认证考试考点——云网络产品
文章目录 腾讯云网络产品功能网络产品概述负载均衡(Cloud Load Balancer)私有网络(Virtual Private Cloud,VPC)专线接入弹性网卡(多网卡热插拔服务)NAT网关(NAT Gateway)…...

Miniled透明屏:超薄、轻便,还有哪些特点?
Miniled透明屏是一种新型的显示屏技术,它采用了微小的LED灯珠作为显示单元,通过透明的材料进行封装,使得整个屏幕具有透明的特性。Miniled透明屏具有以下几个特点: 首先,Miniled透明屏具有高亮度和高对比度的特点。 由…...

MySQL 极速安装使用与卸载
目录 mysql-5.6.51 极速安装使用与卸载 sqlyog工具 mysql简化 mysql-8.1.0下载配置 再完善 mysql-5.6.51 极速安装使用与卸载 mysql-8.1.0下载安装在后 mysql中国官网 MySQLhttps://www.mysql.com/cn/ 点击MySQL社区服务器 点击历史档案 下载完 解压 用管理员运行cmd&a…...

举个栗子!Tableau 技巧(256):灵活折叠文本表的多级数据行
通常,Tableau 默认的图表分层结构是统一打开或关上,有什么办法可以按需选择展开或折叠?如下示例:单击“”展开层级,单击“-“收起层级。 可以试试集操作!今天的栗子,就来分享具体实现方法吧~ 本…...

Android View 初始化完成后,如果再调用measure再设置点击事件则点击事件会失效的解决方案
比如LinearLayout 或RecyclerView 我们在初始化完成并加载完数据后再次调用measure计算高度再setLayoutParams 会导致后面设置的点击事件失效。 比如: RecyclerView rv_select dialog.findViewById(R.id.rv_select); //点击事件rv_select.setOnItemClickListener(n…...

客户端电脑使用 FTP的Cadence_CIS库方法说明 (下)
简介:随着企业的规模扩大,硬件工程师的增多,使用统一服务器上的库管理,可以减少设计错误,提高效率。 使用在FTP上布局Cadence_CIS库,是目前的主流的做法之一; 本文方法,用于已经配置…...

【ES】笔记-let 声明及其特性
let 声明及其特性 声明变量 变量赋值、也可以批量赋值 let a;let b,c,d;let e100;let f521,giloveyou,h[];变量不能重复声明 let star罗志祥;let star小猪;块级作用域,let声明的变量只在块级作用域内有效 {let girl周杨青;}console.log(girl)注意:在 i…...

wps 预加载项插件本地开发启动项目打开wps 客户端,未看到加载项菜单,
wps 预加载项插件本地开发启动项目打开wps 客户端,未看到加载项菜单,请检查本地c盘安装目录下“jsplugins.xml”信息是否添加成功 如下图 name 插件项目 url 本地插件运行地址及端口 <jsplugins><jspluginonline name"wps-soft-copyright…...

uni-app开发微信小程序经常遇到的一些问题及解决方案
1.如何获取用户信息? 可以使用uni.getUserInfo接口获取用户信息。需要用户授权。 2.如何实现下拉刷新? 可以使用uni-app提供的页面组件内置下拉刷新功能,也可以自定义下拉刷新组件。 3.如何实现上拉加载更多? 可以在页面onReachBo…...

一个 git 仓库下拥有多个项目的 git hooks 配置方案
前言 通常情况下,一个 git 仓库就是一个项目,只需要配置一套 git hooks 脚本就可以执行各种校验任务。对于 monorepo 项目也是如此,monorepo 项目下的多个 packages 之间,它们是有关联的,可以互相引用,所以…...

钉钉对接打通金蝶云星空获取流程实例列表详情(宜搭)接口与其他应收单接口
钉钉对接打通金蝶云星空获取流程实例列表详情(宜搭)接口与其他应收单接口 对接系统钉钉 钉钉(DingTalk)是阿里巴巴集团专为中国企业打造的免费沟通和协同的多端平台,提供PC版,Web版和手机版,有考…...

用python做一个小项目,python做简单小项目
大家好,本文将围绕用python做一个小项目展开说明,python做简单小项目是一个很多人都想弄明白的事情,想搞清楚python入门小项目需要先了解以下几个事情。 来源丨网络 经常听到有朋友说,学习编程是一件非常枯燥无味的事情。其实&…...

输入筛选框搜索
文章目录 输入筛选框实现效果图需求前端工具版本添加依赖main.js导入依赖 代码 后端代码对应 sql对应 mapper.xml 文件的动态 sql 输入筛选框实现 效果图 需求 通过筛选框,选择公司,传入后端,后端根据公司名称去文章的内容中进行模糊查询 …...

公司植物日常护养方法备忘录
植物为我们净化空气,美化环境,我们要按照科学的经验照顾好它们。公司植物日常通用护养方法如下: 首先剪掉已经枯黄的部分。 需要晒太阳的植物按时搬到外面晒太阳,每次晒1到2个小时。 所有植物统一在每个月的20号左右施肥一次&am…...

小红书JAVA后端一面汇总总结
小红书 2 年社招 Java 后端一面的面经,面试的风格是从一个知识一层一层深入问到底层。 从 Java IO,问到 socket 底层。从 Java 内存,问到操作系统内存。所以学习知识的时候,不要只 看八股文,还是需要从点到面一层层去掌握, 才能比较好应对这类的面试场景。 问题记录 自我…...

【图论】强连通分量进阶
一.作用 强连通分量可以判断环和进行缩点。还有一系列作用.... 这篇文章介绍缩点 二.题目 https://www.luogu.com.cn/problem/P2341 三.思路 我们分析可以知道当一个点没有出度时,则为最受欢迎的牛。但如果有多个出度,则没有最受欢迎的牛。 这是只有…...