数据结构----顺序表

在学习顺序表之前,我们先来了解一下数据结构。

数据是什么呢?

我们在生活中常见的名字,数字,性别等都属于数据。

结构又是什么呢?

在计算机中,结构就是用来保存数据的方式。

总的来说,数据结构就是计算机存储和组织数据的方式。

1.顺序表

顺序表是数据结构中的一种,也就是说顺序表是一种用来存储和组织数据的一种结构,并且顺序表的底层本质就是数组,只不过顺序表是在数组的的基础上,增加了增删查改的方法,也就是说顺序表里面已经提供了对数据进行增删查改的现成的方法。只不过顺序表里面的增删查改的方法需要我们通过代码来实现,实现顺序表里面的增删查改的代码之后,以后我们实现对通讯录里面数据的增删查改的操作直接用就行了。

同时顺序表是线性表的一种。

1.1线性表

线性表就是具有相同特性的的数据结构的集合。

数据结构是否具有相同特性是从物理结构和逻辑结构来判断。

物理结构:数据在内存中存储的样子。由于我们无法得知计算机是如何给数据分配内存的,所以数据结构有连续和不连续的两种。

逻辑结构:逻辑结构一定是连续的。逻辑结构是我们抽象想象的。

比如排队的时候,我们排对的时候可能排的不是一条直线,但是我们还是得一个一个按序付钱,虽然看起来是不连续的,但在逻辑上我们将其抽象想象成线性的。

前面我们提到,顺序表的底层结构就是数组,而数据又是一块连续的空间,所以顺序表在物理结构和逻辑结构上都是连续的。

 

2.顺序表的分类

我们将顺序表分为了两种,分别为静态顺序表动态顺序表。

2.1 静态顺序表

静态顺序表简单来说就是一个定长的数组。

如下图

1255d2824f2c4bb0af1ed8d5b340029a.png

此时Seqlist就是一个静态顺序表,该顺序表能储存的数据个数大小已经确定,其只能存储100个数据。

2.1动态顺序表

动态顺序表就是一个未定长的数组,也就是动态顺序表里面的数组能存储数据的个数是未定的,但是动态顺序表能存储的数据个数是可以根据实际情况实现动态改变的。

d73fc86872a74f9581c4c3e79924a40d.png

那上面两种顺序表哪种更好用呢?

肯定是动态顺序表。因为它能够根据实际情况来动态实现增容或删除数据。

3.动态顺序表的的实现

由于顺序表的属性有点多,所以我们要用结构体来实现顺序表。

当我们实现动态顺序表的时候我们要分多个文件来实现。如下图

1594fdd1785540ceb1043213e09e269c.png

3.1 动态顺序表的创建和声明

typedef int SLDataType;  //方便以后修改要存储的数据类型
struct SeqList
{SLDataType* arr;int size;  //有效的数据个数顺序表里面int capacity;  //顺序表的总大小
};
typedef struct SeqList SL; 

在一个头文件里面实现动态顺序表的声明。这里我们要将顺序表里面要存储的数据类型重命名为SLDataType,是为了以后方便修改要存储的数据类型,并且也将顺序表重命名为SL,方便后面的操作。

3.2动态顺序表的初始化

在.c源文件实现初始化

void SLInit(SL* sl)
{sl->arr = NULL;sl->size = 0;sl->capacity = 0;
}

ec01091d4d25487b99bf074eaf2240bc.png

需要注意的是,我们进行传参的时候要将sl的地址传过去。我们知道形参是实参的拷贝,我们对形参的改变是不会影响实参的,不会影响实参,初始化就会失败所以我们要将sl的地址传过去,通过指针来实现初始化 。

8ffdfe40345e49adba5f2798db992441.png

通过调试,我们发现顺序表初始化成功了。

3.2 销毁动态顺序表

因为后面涉及到扩容等问题,要用到realloc函数,申请空间,完成程序之后我们要将申请的空间还给计算机,我们这里先把顺序表的销毁讲了,方便以后操作。

void SLBreak(SL* sl)
{if (sl->arr){free(sl->arr);}sl->size = 0;sl->capacity = 0;
}

3.3 数据插入

将数据插入顺序表中有两种方法,分别是尾插和头插。

3.3.1 尾插

什么是尾插呢?

尾插就是从顺序表的尾部插入数据。如下图

63fc300e4f8548609e1fb5c35d602782.png

此时的size==4,我们可能就会想到所以只要将ps->arr[size]改为想要插入的之就行了 。写出以下代码

void SLPushBack(SL* sl, SLDataType x)
{sl->arr[sl->size] = x;
}

但事情并没有那么简单。

我们要知道插入数据时,首先要清楚顺序表内有没有足够的空间来存储插入的数据呢?一开始我们已经将顺序表的内存大小设置为0,这时侯肯定是没有空间插入数据的,所以这时候我们要向内存申请空间,并且以后我们要根据实际情况来实现扩容,所以这时候最好的选择是通过realloc函数来申请空间。

接着再来分析,我们要申请多大的空间呢?

一搬来说,是原来capacity的两倍或者三倍是最好的的选择。

但原来的capacity为0,所以这时候要用上三目操作符。

尾插代码如下

void SLPushBack(SL* sl, SLDataType x)
{assert(sl);if (sl->size == sl->capacity){//实现扩容int SLNewCapacity = sl->capacity == 0 ? 4 : 2 * sl->capacity;SLDataType* tmp =(SLDataType*) realloc(sl->arr, SLNewCapacity * sizeof(SLDataType));//判断空间是否申请成功if (tmp==NULL){perror("realloc fail");exit(1);}//代码运行到这里,空间就申请成功了sl->arr = tmp;sl->capacity = SLNewCapacity;}sl->arr[sl->size] = x;sl->size++;
}

易错点:扩容那里后面是两个==。

 我们需要注意的是我们申请空间成功时返回的地址不能直接传给原来顺序表的数组,因为申请空间会存在失败的情况,空间申请失败就会退出程序,并销毁该空间了。假设我们之前的顺序表已经存有数据,但因为空间申请失败也把原来的空间释放掉,那么原来的数据也没了,这就功亏一篑了,所以我们要设计一个中间变量存储申请空间返回的地址,有这个中间变量来判断空间是否申请成功。

由于我们插入了数据,不要忘了让size的个数进行增加。

3.3.2 头插

什么是头插呢?

头插就是从顺序表的头部插入一个数据。

下面来分析一下如何实现头插。

59731d29ed6244f49c61eaa16f847859.png

假设上图是我们要进行头插的一个数组?

我们要将一个数据插入1的位置,那么我们就要将原有的数据向后移一位。如下图

2a69ca80fd8e4aaab72e8a5a79e65afa.png

既然插入数据,我们就涉及到空间申请了,这里的空间申请于尾插的一莫一样,既然一样,那我们干脆把空间申请的那部分代码单独写为一个函数,需要的时候调用这个函数就行了。

空间申请的代码如下

void SLSpace(SL* sl)
{assert(sl);if (sl->size == sl->capacity){//实现扩容int SLNewCapacity = sl->capacity == 0 ? 4 : 2 * sl->capacity;SLDataType* tmp = (SLDataType*)realloc(sl->arr, SLNewCapacity * sizeof(SLDataType));if (tmp == NULL){perror("realloc fail");exit(1);}//代码运行到这里,空间就申请成功了sl->arr = tmp;sl->capacity = SLNewCapacity;}
}

尾插代码

void SLPushHead(SL* sl, SLDataType x)
{assert(sl);//调用空间申请函数SLSpace(sl);//实现顺序表原数据向后移1位for (int i = sl->size; i > 0; i--){sl->arr[i] = sl->arr[i - 1];//arr[1]=arr[0]}sl->arr[0] = x;sl->size++;
}

运行效果如下图,头插的数据为5。

4b6c1f2b18a745ffb76c090d28b52099.png

3.4.数据删除

既然有数据的插入,那么就有数据的删除。删除我们也分为尾删头删的两种。

3.4.1 尾删

什么是尾删?

尾删就是将顺序表里面的的最后一个元素删除掉。

465d00ffed8f4f8389eb8f20bb27e750.png

如上图,尾删将4给除掉了。

代码实现

void SLPopBack(SL* sl)
{assert(sl);assert(sl->size);  //检测顺序表不为空sl->size--;
}

尾删我们直接让size( 顺序表中的有效个数)减减就行了。我们没必要将要尾删的数据改为其他,我们只要求尾删的操作不影响后面的增删查改的操作就行了。

运行效果

c4d2832165374ad595bdc6f56d295d42.png

3.4.2 头删

什么是头删呢?

头删就是将顺序表的第一个元素删除掉 。

eb4632f13a9b4a068f8da951c8fb4764.png

头删如上图所示,也就是将第一个元素除外其他元素向前移动一位。

代码实现 

void SLPopHead(SL* sl)
{assert(sl);assert(sl->size);//实现数据向前移动一位for (int i = 0; i<sl->size-1; i++){sl->arr[i] = sl->arr[i + 1];  //arr[2]=arr[3]}sl->size--;
}

运行效果

30b1ec68d75a449db11afb822975d488.png

3.5 在指定位置插入数据

分析如何实现?

思路:将指定位置的数据及以从后向前的顺序向后移动一位。

如下图

4cd8c68bfc26492596a41558b1a42245.png

代码实现

 

void SLPopPos(SL* sl, int pos, SLDataType x)
{assert(sl);assert(sl->size && pos <= sl->size);//插入数据之前要申请空间SLSpace(sl);for (int i = sl->size; i > pos; i--){sl->arr[i] = sl->arr[i - 1];}sl->arr[pos] = x;sl->size++;
}

运行效果

31b8e5fdbb4f44fb9bba6ace53a2b049.png

3.6 在指定位置删除数据

 思路

将指定位置之后的数据向前移动一位。

如下图

195180e0bd55478a92ad80eaaacb2731.png

代码实现

void SLPopPos(SL* sl, int pos)
{assert(sl&&sl->size);assert(pos && pos < sl->size);for (int i = pos; i<sl->size-1; i++){sl->arr[pos] = sl->arr[pos + 1];}sl->size--;
}

运行效果

84665d2439864f168b556732e63dd126.png

3.7 查找数据

代码实现

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

运行效果

a6e21b25e3fe44cfbb2d3e58974795de.png

 这里就结束了对顺序表的介绍

下面给大家列处全部代码

test.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
int main()
{SL sl;  //创建一个结构体变量SLInit(&sl);SLPushBack(&sl, 1);SLPushBack(&sl, 2);SLPushBack(&sl, 3);SLPushBack(&sl, 4);SLPrint(sl);SLPushHead(&sl, 5);SLPrint(sl);SLPopBack(&sl);SLPrint(sl);SLPopHead(&sl);SLPrint(sl);SLPushPos(&sl, 1, 3);SLPrint(sl);SLPopPos(&sl, 2);SLPrint(sl);int find = SLFind(&sl, 3);if (find < 0){printf("不存在");}else{printf("数据位于下标为%d",find);}//要在顺序表销毁之前完成增删查改的操作SLBreak(&sl);return 0;
}

SeqList.h

#include <assert.h>
typedef int SLDataType;  //方便以后修改要存储的数据类型
struct SeqList
{SLDataType* arr;int size;int capacity;
};
typedef struct SeqList SL; 
void SLInit(SL* sl);
void SLPrint(SL sl);
void SLBreak(SL* sl);
void SLPushHead(SL* sl, SLDataType x);
void SLPushBack(SL* sl, SLDataType x);
void SLPopBack(SL* sl);
void SLPopHead(SL* sl);
void SLPushPos(SL* sl, int pos, SLDataType x);
void SLPopPos(SL* sl, int pos);
int SLFind(SL* sl, SLDataType x);

Seqlist.c

#define _CRT_SECURE_NO_WARNINGS 1
#include "SeqList.h"
void SLInit(SL* sl)
{sl->arr = NULL;sl->size = 0;sl->capacity = 0;
}
void SLSpace(SL* sl)
{assert(sl);if (sl->size == sl->capacity){//实现扩容int SLNewCapacity = sl->capacity == 0 ? 4 : 2 * sl->capacity;SLDataType* tmp = (SLDataType*)realloc(sl->arr, SLNewCapacity * sizeof(SLDataType));if (tmp == NULL){perror("realloc fail");exit(1);}//代码运行到这里,空间就申请成功了sl->arr = tmp;sl->capacity = SLNewCapacity;}
}
void SLPrint(SL sl)
{for (int i = 0; i < sl.size; i++){printf("%d ", sl.arr[i]);}printf("\n");
}
void SLBreak(SL* sl)
{if (sl->arr){free(sl->arr);}sl->arr = NULL;sl->size = 0;sl->capacity = 0;
}
void SLPushBack(SL* sl, SLDataType x)
{SLSpace(sl);sl->arr[sl->size] = x;sl->size++;
}
void SLPushHead(SL* sl, SLDataType x)
{assert(sl);//调用空间申请函数SLSpace(sl);//实现顺序表原数据向后移1位for (int i = sl->size; i > 0; i--){sl->arr[i] = sl->arr[i - 1];//arr[1]=arr[0]}sl->arr[0] = x;sl->size++;
}
void SLPopBack(SL* sl)
{assert(sl);assert(sl->size);  //检测顺序表不为空sl->size--;
}
void SLPopHead(SL* sl)
{assert(sl);assert(sl->size);//实现数据向前移动一位for (int i = 0; i<sl->size-1; i++){sl->arr[i] = sl->arr[i + 1];  //arr[2]=arr[3]}sl->size--;
}
void SLPushPos(SL* sl, int pos, SLDataType x)
{assert(sl);assert(sl->size && pos <= sl->size);//插入数据之前要申请空间SLSpace(sl);for (int i = sl->size; i > pos; i--){sl->arr[i] = sl->arr[i - 1];}sl->arr[pos] = x;sl->size++;
}
void SLPopPos(SL* sl, int pos)
{assert(sl&&sl->size);assert(pos && pos < sl->size);for (int i = pos; i<sl->size-1; i++){sl->arr[pos] = sl->arr[pos + 1];}sl->size--;
}
int SLFind(SL* sl, SLDataType x)
{assert(sl);for (int i = 0; i < sl->size; i++){if (sl->arr[i] == x){return i;}}return -1;}

 感谢观看。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

相关文章

Python 基础02-Python 入门

官方文档&#xff1a;3.10.13 Documentation 一、Python 代码编写习惯 1. Python 中的编码 在 Python 3 版本之后&#xff0c;Python 默认使用 UTF-8 编码。UTF-8 是一种针对 Unicode 的可变长度字符编码。 2. 注释 注释可以对代码起到解释说明的作用&#xff0c;注释内容…

Linux的启动过程,了解一下?

Linux 系统启动过程 linux启动时我们会看到许多启动信息。 Linux系统的启动过程并不是大家想象中的那么复杂&#xff0c;其过程可以分为5个阶段&#xff1a; 内核的引导。运行 init。系统初始化。建立终端 。用户登录系统。 init程序的类型&#xff1a; SysV: init, CentO…

linux——yum工具详解

yum是linux中自动解决软件包依赖关系的管理器 同时&#xff0c;yum也是一个rpm软件 这里使用yum install nginx安装nginx

CommunityToolkit.Mvvm笔记---ObservableValidator

ObservableValidator 是实现 INotifyDataErrorInfo 接口的基类&#xff0c;它支持验证向其他应用程序模块公开的属性。 它也继承自 ObservableObject&#xff0c;因此它还可实现 INotifyPropertyChanged 和 INotifyPropertyChanging。 它可用作需要支持属性更改通知和属性验证的…

Oracle解析exp、imp及常见的问题

前言 在工作中经常需要不同数据库的导入和导出。exp和imp可以实现数据的迁移。 exo会转储产生对应的二进制文件,里面包括数据的定义信息、数据内容等,即为dump文件。 下面是使用exp和imp的一些场景 exp和imp主要有4中模式: 1)数据库模式 数据库模式也就是我们说的全备…

k8s安装记录

k8s安装记录 如无特别说明&#xff0c;则该步操作指在所有的机器上执行&#xff01;&#xff01;&#xff01; 如无特别说明&#xff0c;则该步操作指在所有的机器上执行&#xff01;&#xff01;&#xff01; 如无特别说明&#xff0c;则该步操作指在所有的机器上执行&#…

CSS——前端笔记

CSS 1、选择器1.1、基础选择器1.2、复合选择器1.2.4、伪类选择器 1.3、属性选择器1.4、结构伪类选择器1.5、伪元素选择器 2、CSS的元素显示模式2.1、块元素2.2、行内元素2.3、行内块元素2.4、元素显示模式转换 3、字体属性3.1、font-family 字体3.2、font-size 字体大小3.3、fo…

Three.js加载glb / gltf模型,Vue加载glb / gltf模型(如何在vue中使用three.js,vue使用threejs加载glb模型)

简介&#xff1a;Three.js 是一个用于在 Web 上创建和显示 3D 图形的 JavaScript 库。它提供了丰富的功能和灵活的 API&#xff0c;使开发者可以轻松地在网页中创建各种 3D 场景、模型和动画效果。可以用来展示产品模型、建立交互式场景、游戏开发、数据可视化、教育和培训等等…

常用的数据结构及算法

一、数据结构 &#xff08;一&#xff09;线性结构&#xff1a;一对一。 1.可以使用数组、链表来表示。数组又分为静态数组和动态数组两种。链表常用的是单链表。 2.两种特殊的线性结构&#xff1a;队列和栈。其中队列是先进先出&#xff08;排队&#xff09;&#xff0c;栈…

SpringBoot3 集成Springdoc 实现Swagger3功能

说明&#xff1a; 只通过引用org.springdoc 的两个包就可以使用Swagger3 功能&#xff08;步骤1&#xff09;&#xff1b;如想更美观及实现动态认证的开启与关闭&#xff0c;及Swagger3登录认证等功能&#xff0c;需实现&#xff08;步骤1、2、3&#xff09;的配置; 1、 引包…

chrome浏览器查看css样式

样式的查看 1.匹配器为灰色文本&#xff1a; 表示非当前选择器 2.样式有划线标识&#xff1a;CSS属性无效或未知 / 属性值无效 / 被其他属性覆盖的属性 3.属性以浅色文本显示且有感叹号提示&#xff1a;属性虽然有效&#xff0c;但由于CSS逻辑而没有任何影响 转自&#xff1a;…

2024HW --->蓝队面试题

这段时间在写横向移动&#xff0c;搞得鸽了很久&#xff08;内网真的很玄学&#xff09; 还没写完。。。 但是这不是准备HW了吗。小编也来整理一下自己收集到的题目吧&#xff01;&#xff01;&#xff01; &#xff08;仅为个人见解&#xff0c;不代表最终答案&#xff09;&…

react中useState的值没有改变,而是旧的数值

问题背景 想实现点击按钮就改变数据的效果&#xff0c;但是在控制台的打印结果&#xff0c;总是上一次的修改情况&#xff0c;并不是最新的修改后的数据 代码&#xff1a; import { useState, useRef } from "react";// 实现sonA的数据传递给sonB const SonA () …

C语言联合体详解

下午好诶&#xff0c;今天小眼神给大家带来一篇C语言联合体详解的文章~ 目录 联合体 1. 联合体类型的声明 2. 联合体的特点 代码一&#xff1a; 代码二&#xff1a; 3. 相同成员的结构体和联合体对比 ​编辑4. 联合体大小的计算 5. 联合体的优点 联合体 1. 联合体…

第62天:服务攻防-框架安全CVE 复现SpringStrutsLaravelThinkPHP

目录 思维导图 常见语言开发框架&#xff1a; 案例一&#xff1a;PHP-开发框架安全-Thinkphp&Laravel Thinkphp3.2.x日志泄露 自动化脚本检测 如何getshell 手工注入 ​ThinkPHP5 5.0.23 手工注入 工具检测 laravel-cve_2021_3129 案例二&#xff1a;JAVAWEB-开…

pytorch与深度学习

ChatGPT PyTorch是一个由Facebook AI Research Team开发的开源深度学习库&#xff0c;它提供了一个灵活的环境和丰富的API&#xff0c;用于快速且方便地构建、训练和部署深度学习模型。PyTorch在科学界和工业界都收到了广泛的使用&#xff0c;其中包括了学术研究、小型项目和大…

Chrome修改主题颜色

注意&#xff1a;自定义Chrome按钮只在搜索引擎为Google的时候出现。

如何30天快速掌握键盘盲打

失业后在家备考公务员&#xff0c;发现了自己不正确的打字方式&#xff0c;决定每天抽出一点时间练习打字。在抖音上看到一些高手的飞速盲打键盘后&#xff0c;觉得使用正确的指法打字是很必要的。 练习打字&#xff0c;掌握正确的键盘指法十分关键。 练习打字的第一步是找到…

关于电商独立站搭建中电商API数据采集接口的应用

搭建供应链系统时&#xff0c;您可能需要与电商平台进行集成&#xff0c;以实现订单管理、库存同步、物流跟踪等功能。以下是一些常见的电商接口&#xff0c;可以帮助您构建供应链系统&#xff1a; 1. **淘宝开放平台接口**&#xff1a;淘宝开放平台提供了丰富的接口&#xff…

AI System AI系统对大模型的影响有多深?

AI System AI系统对大模型的影响有多深&#xff1f;要回答这个问题之前&#xff0c;不妨从下面这个问题开始入手思考。 大模型进入了爆发期后&#xff0c;在 LLM 进化树中&#xff0c;BERT&#xff08;Encoder-Only&#xff09;、T5&#xff08;Encoder-Decoder&#xff09;、…