顺序表详解(如何实现顺序表)

文章目录


前言

在进入顺序表前,我们先要明白,数据结构的基本概念。


一、数据结构的基本概念

1.1什么是数据结构

数据结构是由“数据”和“结构”两词组合而来。所谓数据就是?常见的数值1、2、3、4.....、姓名、性别、年龄,等。这些都是数据。所谓结构就是当我们想要使用大量同⼀类型的数据时,我们可以借助数组这样的数据结构将大量的数据组织在⼀起,结构也可以理解为组织数据的方式。

1.2数据结构的两个层次

数据结构的两个层次分为逻辑结构和存储结构,逻辑结构与数据的存储无关独立于计算机从具体问题抽象出来的数学模型模。逻辑结构分为线性结构和非线性结构,这里不再强调。存储结构分为顺式存储结构和链式存储结构,今天我们所说的顺序表就是顺数存储结构,链式存储结构的代表就是链表。

1.3最基础的数据结构:数组

二.顺序表的概念及结构

概念:之前说了最基础的数据结构就是数组,它的概念:顺序表其实就是数组,但是在宿主的基础上,他还要求数据必须从头开始连续存放,并且中间不能跳跃间隔

2.1结构

 顺序表它分为静态顺序表和动态顺序表

静态顺序表

静态顺序表需要用#define来开辟,静态的特点就是N给小了不够用,给大了又浪费,所以我们所说的顺序表一般都是指的动态顺序表。

动态顺序表

2.2接口函数

接口函数就是某个模块写了(主要)给其它模块用的函数。简单的说接口函数就是类中的公有数。顺序表的实现主要是以接口函数来实现的

三.动态顺序表的实现

顺序表(seplist),我们重命名为SL,完成这个它我们使用3个文件,SL.h来放函数的声明,SL.cpp来放函数的定义,test.c来放可执行程序。

3.1一个经典的错误(初始化)

void SLInit(SL ps)
{ps.a = NULL;ps.size = ps.capacity = 0;}void testSL1()
{SL S1;SLInit(SL);
}

为什么这个代码无法运行???

因为在函数中的形参跟实参是有区别的形参的改变,不会影响到实参的,形参只是实参的一份临时拷贝,所以要用指针来找地址。

所以正确的初始化应该要这样

void SLInit(SL* ps)
{ps->a = NULL;ps->size = ps->capacity = 0;}void testSL1()
{SL S1;SLInit(&SL);
}

3.2接口函数之尾插

在一个数组中,如果我们想在末尾插入一个数,我们该怎么插入呢?这就是我们要想如何完成这个接口函数。

往末尾插东西,我们就要做到3点考虑,一.没有空间,刚刚好,二.空间不够的时候要进行扩容,三.空间足够的时候我们就直接插入。

先来看最容易的情况就是直接尾删

void SLpushBack(SL* ps, SLDataType x)
{ps->a[ps->size] = x;ps->size++;
}

然后我们在想我们前三点要注意的事情,如果没有空间或者空间不足了的话,我就要扩容,我们可以先将有效个数和空间容量相等来形成一个新的有效空间,这里我用了一个三目操作符,如果他们都等于零,我就给他付个值不等于零,我就翻倍在这个地方的扩容,我们就能想到realloc函数的扩容。过完之后我们还要判断一下,如果为空指针的话我们就要报警告,最后把我开辟的新空间重新付给a就可以了。

void SLPushBack(SL* ps, SLDataType x)
{if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));if (tmp == NULL){printf("realloc fail\n");exit(-1);}ps->a = tmp;ps->capacity = newcapacity;}ps->a[ps->size] = x;ps->size++;}

其实扩容这一步,我们完成了另外一种接口函数的使用,那就是检查扩容,我们可以用一个步骤来开辟一个新的结构函数就是检查扩容void SLCheckCapacity(SL* ps);这样对于后面的来使用就会更加方便。

3.3接口函数之尾删

尾删就非常简单了,我们只要防止数组越界就可以了,我们这里利用断言来警告他不能越界。

void SLPopBack(SL* ps)
{assert(ps->size > 0);{ps->size--;}
}

3.4接口函数之头插

头插的话想在第一个数前放一个位置,我们就把已经存放的数每个都向后移一个,注意:如果容量空间已到最大则需开辟空间,所以这就用到了我们之前所讲的检查扩容这个接口函数,所以在头差之前我们先要来检查一下扩容,如果容量够就可以进行头差,如果不够就扩容。

void SLPushFront(SL* ps, SLDataType x)
{SLCheckCapacity(ps);//挪动数据int end = ps->size - 1;while (end >= 0){ps->a[end + 1] = ps->a[end];end--;}ps->a[0] = x;ps->size++;
}

3.5接口函数之头删

先思考为什么头删不可以size--???

因为根据顺序表的概念必须从头开始连续存放,并且中间不能跳跃间隔。

所以这个地方我们采取先挪动在尾删的方式。

void SLPopFront(SL* ps)
{assert(ps->size > 0);//挪动数据int begin = 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;
}

3.6还原空间

因为我们之前动态开辟了内存,所以说我们肯定要把这个内存进行释放。

void SLDestory(SL* ps)
{free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0;
}

3.7接口函数之查找

查找的意思就是说找到对应元素所在的下标,即便他有多个也没关系,顺序表是从头到尾开始存放的,但是存放的内容不一定需要从头到尾他还可以存放字符等各种变量。

int SLFind(SL* ps, SLDataType x)
{for (int i = 0; i < ps->size; i++){if (ps->a[ps->size] == x){return i;}}return -1;
}

3.8接口函数之在指定的pos下标位置插入

pos下标也是有要求,他不可以违背顺序表的概念

其实挪动方法都是一样的,不管是尾插还是头插它的移动方法其实是一样的

void SLInsert(SL* ps, int pos, SLDataType x)
{assert(pos >= 0 && pos <= ps->size);SLCheckCapacity(ps);int end = ps->size - 1;while(end >= pos){ps->a[end + 1] = ps->a[end];end--;}ps->a[pos] = x;ps->size++;
}

3.9接口函数之删除pos下标位置的数据

其实挪动方法都是一样的,不管是尾插还是头插它的移动方法其实是一样的,挪动的方式是一样的,只是可能方向不一样,做法是一样的,然后我们还是要判断下标的合法性

void SLErase(SL* ps, int pos)
{assert(pos >= 0 && pos < ps->size);int begin = pos + 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}
}

4.0复用

这个时候有没有突然间恍然大悟大!!!

之前写的头删尾删头差尾插好像都可以用pos去代替去完善

头删
void PushBack(SL* ps)
{SLErase(ps, ps->0);
}
尾删
void SLPopBack(SL* ps)
{SLErase(ps, ps->size-1);
}
头插
void SLPushFront(SL* ps, SLDataType x)
{SLInsert(ps, ps->0,X);
}
尾插
void SLpushBack(SL* ps, SLDataType x)
{SLInsert(ps, ps->size, X);
}

这就是复用。

四.整体的实现

SL.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//#define N 1000
typedef int SLDataType;
#pragma once
typedef struct SeqList
{SLDataType * a;//动态开辟的数组大小int size; // 有效数据个数int capacity; // 空间容量}SL;
void SLInit (SL* ps);//初始化
void SLPrint(SL* ps);//打印
void SLCheckCapacity(SL* ps);//检查扩容
void SLDestory(SL* ps);//销毁,还原空间
void SLpushBack(SL* ps, SLDataType x);//尾插
void SLPopBack(SL* ps);//尾删
void SLPushFront(SL* ps, SLDataType x);//头插
void SLPopFront(SL* ps);//头删
int SLFind(SL* ps, SLDataType x);//查找
void SLInsert(SL* ps, int pos, SLDataType x);//在指定的pos下标位置插入
void SLErase(SL* ps, int pos);//删除pos位置的数据
SL.cpp
#include"SL.h"
//初始化
void SLInit(SL* ps)
{ps->a = NULL;ps->size = ps->capacity = 0;}//打印
void SLPrint(SL* ps)
{for (int i = 0; i < ps->size; i++){printf("%d", ps->a[i]);}printf("\n");
}//检查扩容
void SLCheckCapacity(SL* ps)
{if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));if (tmp == NULL){printf("realloc fail\n");exit(-1);}ps->a = tmp;ps->capacity = newcapacity;}
}//销毁,还原空间
void SLDestory(SL* ps)
{free(ps->a);ps->a = NULL;ps->capacity = ps->size = 0;
}//尾插
void SLpushBack(SL* ps, SLDataType x)
{ps->a[ps->size] = x;ps->size++;
}//尾删
void SLPopBack(SL* ps)
{assert(ps->size > 0);{ps->size--;}
}//头插
void SLPushFront(SL* ps, SLDataType x)
{SLCheckCapacity(ps);//挪动数据int end = ps->size - 1;while (end >= 0){ps->a[end + 1] = ps->a[end];end--;}ps->a[0] = x;ps->size++;
}//头删
void SLPopFront(SL* ps)
{assert(ps->size > 0);//挪动数据int begin = 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}ps->size--;
}//查找
int SLFind(SL* ps, SLDataType x)
{for (int i = 0; i < ps->size; i++){if (ps->a[ps->size] == x){return i;}}return -1;
}//在指定的pos下标位置插入
void SLInsert(SL* ps, int pos, SLDataType x)
{assert(pos >= 0 && pos <= ps->size);SLCheckCapacity(ps);int end = ps->size - 1;while(end >= pos){ps->a[end + 1] = ps->a[end];end--;}ps->a[pos] = x;ps->size++;
}//删除pos位置的数据
void SLErase(SL* ps, int pos)
{assert(pos >= 0 && pos < ps->size);int begin = pos + 1;while (begin < ps->size){ps->a[begin - 1] = ps->a[begin];begin++;}
}//头删
//void PushBack(SL* ps)
//{
//	SLErase(ps, ps->0);
//}
//尾删
//void SLPopBack(SL* ps)
//{
//	SLErase(ps, ps->size-1);
//}
//头插
//void SLPushFront(SL* ps, SLDataType x)
//{
//	SLInsert(ps, ps->0,X);
//}
//尾插
//void SLpushBack(SL* ps, SLDataType x)
//{
//	SLInsert(ps, ps->size, X);
//}

总结

有了顺序表,为什么还要学习其他的数据结构?顺序表作为数据结构的最基本,假设数据量非常庞大,频繁的获取数字,有效数据个数会影响程序的执行程序所以说最基础的数据结构提供的操作已经不能完全满足复杂的算法实现只有不断地提升自己才能变得强大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/694695.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

开发一款招聘小程序需要具备哪些功能?

随着时代的发展&#xff0c;找工作的方式也在不断变得简单&#xff0c;去劳务市场、人才市场的方式早就已经过时了&#xff0c;现在大多数年轻人都是直接通过手机来找工作。图片 找工作类的平台不但能扩大企业的招聘渠道&#xff0c;还能节省招聘的成本&#xff0c;方便求职者进…

C# 使用onnxruntime部署夜间雾霾图像的可见度增强

目录 介绍 模型信息 效果 项目 代码 下载 C# Onnx 使用onnxruntime部署夜间雾霾图像的可见度增强 介绍 github地址&#xff1a;GitHub - jinyeying/nighttime_dehaze: [ACMMM2023] "Enhancing Visibility in Nighttime Haze Images Using Guided APSF and Gradien…

如何修改unity的背景颜色

要在Unity中将背景颜色设为黑色&#xff0c;可以按照以下步骤进行&#xff1a; 1、在Unity编辑器中&#xff0c;选择你想要修改背景颜色的摄像机对象&#xff08;一般是Main Camera&#xff09;。 2、在Inspector面板中&#xff0c;找到"Clear Flags"&#xff08;清…

ChatGPT 4.0 升级指南

1.ChatGPT 是什么&#xff1f; ChatGPT 是由 OpenAI 开发的一种基于人工智能的聊天机器人&#xff0c;它基于强大的语言处理模型 GPT&#xff08;Generative Pre-trained Transformer&#xff09;构建。它能够理解人类语言&#xff0c;可以为我们解决实际的问题。 1.模型规模…

计网 - 域名解析的工作流程

文章目录 Pre引言1. DNS是什么2. 域名结构3. 域名解析的工作流程4. 常见的DNS记录类型5. DNS安全6. 未来的发展趋势 Pre 计网 - DNS 域名解析系统 引言 在我们日常使用互联网时&#xff0c;经常会输入各种域名来访问网站、发送电子邮件或连接其他网络服务。然而&#xff0c;我…

Java中的关键字

✨✨ 所属专栏&#xff1a; Java基石&#xff1a;深入探索Java核心基础✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; Java中的关键字是一些具有特殊含义的单词&#xff0c;它们在语法中有特定的用途&#xff0c;不能用作标识符&am…

[力扣 Hot100]Day32 随机链表的复制

题目描述 给你一个长度为 n 的链表&#xff0c;每个节点包含一个额外增加的随机指针 random &#xff0c;该指针可以指向链表中的任何节点或空节点。 构造这个链表的 深拷贝。 深拷贝应该正好由 n 个 全新节点组成&#xff0c;其中每个新节点的值都设为其对应的原节点的值。新…

论文导读 | 因式分解数据库

背景和问题定义 在传统的关系型数据库中&#xff0c;二维表格形式容易造成信息的冗余。如果我们将数据库中的每条元组看成单项式&#xff0c;一个关系型数据库就可以表示成这些单项式的和。通过对多项式的因式分解就能够得到更加紧凑的表示形式。 例如&#xff1a;下图中的表…

【设计模式】01-装饰器模式Decorator

作用&#xff1a;在不修改对象外观和功能的情况下添加或者删除对象功能&#xff0c;即给一个对象动态附加职能 装饰器模式主要包含以下角色。 抽象构件&#xff08;Component&#xff09;角色&#xff1a;定义一个抽象接口以规范准备接收附加责任的对象。具体构件&#xff08…

unity打包apk运行于google手机

第一次打包apk运行于Pixel 7 Pro 一直提示安装包无法安装 untiy版本2020.1.0f1 有两点需要注意 第一 Scrpting Backend 需要选择 IL2CPP 勾选 ARM64 第二 勾选 Custom Main Mainfest 在Assets -> Plugins -> Android文件夹下 AndroidMainfest 中增加android:export…

QT3作业

1 2. 使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数&#xff0c;将登录按钮使用t5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#…

iMazing2024Windows和Mac的iOS设备管理软件(可以替代iTunes进行数据备份和管理)

iMazing2024是一款兼容 Windows 和 Mac 的 iOS 设备管理软件&#xff0c;可以替代 iTunes 进行数据备份和管理。以下是一些 iMazing 的主要功能和优点&#xff1a; 数据备份和恢复&#xff1a;iMazing 提供了强大的数据备份和恢复功能&#xff0c;可以备份 iOS 设备上的各种数据…

PWM在STM32中使用指南

什么是PWM? PWM&#xff08;脉冲宽度调制&#xff09;是一种常用来控制模拟电路的技术&#xff0c;通过修改脉冲的宽度&#xff08;即在固定周期内的高电平持续时间&#xff09;来调控输出信号的平均电压。 一个PWM信号主要包括两个部分&#xff1a;一个是占空比&#xff0c;…

四甲基罗丹明-叠氮,5(6)-TAMRA N3,常用的生物标记试剂

您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;四甲基罗丹明-叠氮&#xff0c;Tetramethylrhodamine, TMR&#xff0c;5(6)-TAMRA-azide&#xff0c;5(6)-TAMRA N3 一、基本信息 产品简介&#xff1a;5 (6) - TAMRA azide, also known as tetramethylrhodamine a…

智慧安防/视频监控汇聚平台EasyCVR如何通过接口调用获取设备录像回看的流地址?

视频云存储/视频融合/安防监控EasyCVR视频汇聚系统可兼容各品牌的IPC、NVR、移动单兵、智能手持终端、移动执法仪、无人机、布控球等设备的接入&#xff0c;支持的接入协议包括&#xff1a;国标GB28181、RTSP/Onvif、RTMP&#xff0c;以及厂家的私有协议与SDK&#xff0c;如&am…

全流程点云机器学习(二)使用PaddlePaddle进行PointNet的机器学习训练和评估

前言 这不是高支模项目需要嘛&#xff0c;他们用传统算法切那个横杆竖杆流程复杂耗时很长&#xff0c;所以想能不能用机器学习完成这些工作&#xff0c;所以我就来整这个工作了。 基于上文的数据集切分 &#xff0c;现在来对切分好的数据来进行正式的训练。 本系列文章所用的…

使用 Next.js 连接 mysql 数据库

前言 本文主要为大家介绍&#xff0c;如何使用 Next 框架实现一个简单的后端接口&#xff0c;并且从数据库中请求数据返回给前端。 实现 创建api/getData文件夹 项目创建完成后在 app 文件下新建api文件夹&#xff0c;在 api 文件夹下新建 getData 文件夹&#xff0c;在 ge…

IOT-Reaserch安装ghidra以及IDEA和ghidra的配置

Linux research 5.4.0-91-generic #102~18.04.1-Ubuntu SMP Thu Nov 11 14:46:36 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux java --version IOT自带的java是符合要求的&#xff0c;不需要额外下载 iotresearch:~/install-file$ java --version openjdk 11.0.13 2021-10-19 …

数字新纪元:探索Web3对社会的影响

在当今数字化时代&#xff0c;技术的进步已经成为社会发展的驱动力之一。而随着区块链技术的快速发展&#xff0c;我们正处在一个即将到来的数字新纪元——Web3时代。这一新时代不仅仅是技术的迭代升级&#xff0c;更是对传统社会模式的颠覆和重构。本文将深入探讨Web3对社会的…

深入理解指针(c语言)

目录 一、使用指针访问数组二、数组名的理解1、数组首元素的地址2、整个数组 三、一维数组传参的本质四、冒泡排序五、二级指针六、指针数组 一、使用指针访问数组 可以使用指针来访问数组元素。例如&#xff0c;可以声明一个指针变量并将其指向数组的第一个元素&#xff0c;然…