【数据结构】【版本1.0】【线性时代】——顺序表



快乐的流畅:个人主页


个人专栏:《算法神殿》《数据结构世界》《进击的C++》

远方有一堆篝火,在为久候之人燃烧!

文章目录

  • 引言
  • 一、顺序表的概念
    • 1.1 最基础的数据结构:数组
    • 1.2 数组与顺序表的区别
  • 二、静态顺序表
  • 三、动态顺序表的模拟实现
    • 3.1 定义
    • 3.2 初始化
    • 3.3 销毁
    • 3.4 扩容
    • 3.5 尾插
    • 3.6 头插
    • 3.7 尾删
    • 3.8 头删
    • 3.9 指定插入
    • 3.10 指定删除
    • 3.11 查找
    • 3.12 修改
    • 3.13 打印

引言

数据结构世界——顺序表(Sequential List)

一、顺序表的概念

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

【思考】有了数组,为什么还要学习其他的数据结构?

假定数组有10个空间,已经使用了5个,向数组中插入数据步骤:求数组的长度,求数组的有效数据个数,向下标为数据有效个数的位置插入数据(注意:这里是否要判断数组是否满了,满了还能继续插入吗)…


假设数据量非常庞大,频繁的获取数组有效数据个数会影响程序执行效率。

结论:最基础的数据结构能够提供的操作已经不能完全满足复杂算法实现

1.2 数组与顺序表的区别

顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口。

二、静态顺序表

//静态顺序表
#define N 10
typedef int SLDataType;

typedef struct SeqList
{
	SLDataType a[N];
	int size;
}SL;

​​​​

静态顺序表缺陷空间给少了不够用,给多了造成空间浪费

三、动态顺序表的模拟实现

3.1 定义

//动态顺序表
typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* a;
	int size;//存储的有效数据的个数
	int capacity;//容量
}SL;

顺序表的各种功能,都是通过函数来实现的。

3.2 初始化

void SLInit(SL* psl)
{
	assert(psl);
	psl->a = (SLDataType*)malloc(sizeof(SLDataType) * 4);
	if (psl->a == NULL)
	{
		perror("malloc fail");
		return;
	}
	psl->size = 0;
	psl->capacity = 4;
}
  • 函数参数传结构体指针,这样才能在函数内部对顺序表进行各种解引用操作
  • 对于动态顺序表,初始化则用malloc函数动态开辟内存空间 ;存储个数为0,容量初始置为4

3.3 销毁

void SLDestroy(SL* psl)
{
	assert(psl);
	free(psl->a);
	psl->a = NULL;
	psl->size = 0;
	psl->capacity = 0;
}
  • 对于用free函数将动态开辟的空间进行释放,并将指针置为NULL ;再将存储个数和容量置为0

3.4 扩容

数组满了怎么办?那么,我们就需要扩容,定义一个函数专门来检测容量,如果容量满了,则进行扩容。

static void CheckCapacity(SL* psl)
{
	assert(psl);
	if (psl->size == psl->capacity)
	{
		SLDataType* tmp = (SLDataType*)realloc(psl->a, sizeof(SLDataType) * psl->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}
		psl->a = tmp;
		psl->capacity *= 2;
	}
}
  • 我们使用realloc函数动态开辟空间进行扩容,而扩容的大小则为原来容量的2倍 (这样比较合理,扩容多了浪费空间,扩容少了空间又不够)

3.5 尾插

void SLPushBack(SL* psl, SLDataType x)
{
	assert(psl);
	CheckCapacity(psl);
	psl->a[psl->size++] = x;
}
  • 对于psl指针,如果有人误传了NULL,则会导致程序崩溃,所以最好在每个函数前断言assert,保证psl指针的有效性
  • 先检测是否需要扩容
  • 再根据当前已有的元素个数,对数组进行下标访问并赋值,size++

3.6 头插

void SLPushFront(SL* psl, SLDataType x)
{
	assert(psl);
	CheckCapacity(psl);
	int end = psl->size - 1;
	while (end >= 0)
	{
		psl->a[end + 1] = psl->a[end];
		end--;
	}
	psl->a[0] = x;
	psl->size++;
}
  • 先检测是否需要扩容
  • 再用循环将数组中每个元素向后挪动一格,最后在头部插入数据,size++

3.7 尾删

void SLPopBack(SL* psl)
{
	assert(psl);
	assert(psl->size > 0);
	psl->size--;
}
  • 使用断言assert,保证size大于零,不会造成越界访问
  • 直接让size- -,使得不再能够访问尾部数据

3.8 头删

void SLPopFront(SL* psl)
{
	assert(psl);
	assert(psl->size > 0);
	int start = 0;
	while (start < psl->size - 1)
	{
		psl->a[start] = psl->a[start + 1];
		start++;
	}
	psl->size--;
}
  • 用循环将数组中每个元素向前挪动一格,覆盖头部数据,实现头部删除,size- -

3.9 指定插入

void SLInsert(SL* psl, int pos, SLDataType x)
{
	assert(psl);
	assert(pos >= 0 && pos <= psl->size);
	CheckCapacity(psl);
	int end = psl->size - 1;
	while (end >= pos)
	{
		psl->a[end + 1] = psl->a[end];
		end--;
	}
	psl->a[pos] = x;
	psl->size++;
}
  • 断言assert保证pos不会越界
  • 输入指定位置的下标,用循环将pos往后的所有数据向后挪动一格 ,再于指定位置插入数据,size++

我们可以运用这个应用更广的指定插入,来实现头插和尾插 ,以此增强函数的复用性

尾插

void SLPushBack(SL* psl, SLDataType x)
{
	assert(psl);
	SLInsert(psl, psl->size, x);
}

头插

void SLPushFront(SL* psl, SLDataType x)
{
	assert(psl);
	SLInsert(psl, 0, x);
}

3.10 指定删除

void SLErase(SL* psl, int pos)
{
	assert(psl);
	assert(pos >= 0 && pos < psl->size);
	int start = pos + 1;
	while (start < psl->size)
	{
		psl->a[start - 1] = psl->a[start];
		start++;
	}
	psl->size--;
}
  • 断言assert保证pos不会越界(此处与指定插入比少了一个等号,仔细思考一下为什么?)
  • 输入指定位置的下标,用循环将pos往后的所有数据向前挪动一格 ,以此覆盖pos位置的数据,达到指定删除的目的

我们可以运用这个应用更广的指定删除,来实现头删和尾删 ,以此增强函数的复用性

尾删

void SLPopBack(SL* psl)
{
	assert(psl);
	SLErase(psl, psl->size - 1);
}

头删

void SLPopFront(SL* psl)
{
	assert(psl);
	SLErase(psl, 0);
}

3.11 查找

int SLFind(SL* psl, SLDataType x)
{
	assert(psl);
	int i = 0;
	for (i = 0; i < psl->size; i++)
	{
		if (psl->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}
  • for循环遍历数组,找到返回下标,找不到返回-1

3.12 修改

void SLModify(SL* psl, int pos, SLDataType x)
{
	assert(psl);
	assert(pos >= 0 && pos < psl->size);
	psl->a[pos] = x;
}
  • 直接通过下标访问数组进行修改

3.13 打印

void SLPrint(SL* psl)
{
	assert(psl);
	int i = 0;
	for (i = 0; i < psl->size; i++)
	{
		printf("%d ", psl->a[i]);
	}
}

真诚点赞,手有余香

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于STM32F030设计的多点温度采集系统(BC26+OneNet)

一、项目背景 随着物联网技术的迅猛发展&#xff0c;越来越多的智能设备应运而生&#xff0c;而温度采集系统是其中重要的一类。在现代工业和家庭生活中&#xff0c;温度对于生产、居住和储存等过程的控制有着非常重要的作用。因此&#xff0c;准确地采集环境温度数据并进行处…

Ubuntu基础 - 常用命令

目录 一.打开终端 1.快捷键 2.右键桌面 3.应用程序管理 二. 常用命令 1. ls命令 2. cd 命令 3. pwd 命令 4. mkdir 命令 5. rm 命令 和 rmdir 命令 6. mv 命令 7. cp 命令 8. touch 9. more 命令 less 命令 10. echo > 前言:大家好,这是一篇ubuntu常用的基…

进程概念(二)

目录 进程优先级基本概念查看系统进程PRI and NIPRI vs NI修改进程优先级的命令renice修改优先级进程其他概念 环境变量基本概念查看环境变量方法常见环境变量PATHHOMESHELL 查看环境变量环境变量相关的命令 环境变量特征命令行参数main函数中的俩个参数 argc argvmain函数的第…

机器学习--生成式模型和判别式模型的具体分析

文章目录 生成式模型和判别式模型的具体分析生成式模型定义工作原理优点缺点常见模型 判别式模型 总结生成式模型判别式模型 生成式模型和判别式模型的具体分析 生成式模型和判别式模型在机器学习中有着不同的目标、应用场景和性能特点。以下将详细分析它们的定义、工作原理、…

Golang-分离式加载器(传参)AES加密

目录 enc.go 生成: dec.go --执行dec.go...--上线 cs生成个c语言的shellcode. enc.go go run .\enc.go shellcode 生成: --key为公钥. --code为AES加密后的数据, ----此脚本每次运行key和code都会变化. package mainimport ("bytes""crypto/aes"&…

【Vue】核心概念 - module

目标 掌握核心概念 module 模块的创建 问题 由于使用单一状态树&#xff0c;应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时&#xff0c;store 对象就有可能变得相当臃肿。 这句话的意思是&#xff0c;如果把所有的状态都放在state中&#xff0c;当项目变得…

解锁ChatGPT:从GPT-2实践入手解密ChatGPT

⭐️我叫忆_恒心&#xff0c;一名喜欢书写博客的研究生&#x1f468;‍&#x1f393;。 如果觉得本文能帮到您&#xff0c;麻烦点个赞&#x1f44d;呗&#xff01; 近期会不断在专栏里进行更新讲解博客~~~ 有什么问题的小伙伴 欢迎留言提问欧&#xff0c;喜欢的小伙伴给个三连支…

虚拟机开启网络代理设置

前言&#xff1a; 不管是物理主机还是实验环境中的VMware虚拟机&#xff0c;有时候总要访问一些镜像网站或者资源网站拉取一些学习资料&#xff0c;但由于国内外网络环境的差异和网络安全的问题。总是会被阻拦。物理机相对比较容易一些&#xff0c;今天我们来说一说虚拟机应该…

Java——IO流(一)-(2/9):File类的常用方法(判断文件类型、获取文件信息、创建删除文件、遍历文件夹)

目录 常用方法1&#xff1a;判断文件类型、获取文件信息 方法 实例演示 常用方法2&#xff1a;创建文件、删除文件 方法 实例演示 常用方法3&#xff1a;遍历文件夹 方法 实例演示 常用方法1&#xff1a;判断文件类型、获取文件信息 方法 File提供的判断文件类型、获…

【数据结构(邓俊辉)学习笔记】图06——最小支撑树

文章目录 0. 概述1. 支撑树2. 最小支撑树3. 歧义性4. 蛮力算法5. Prim算法5.1 割与极短跨越边5.2 贪心迭代5.3 实例5.4 实现5.5 复杂度 0. 概述 学习下最小支撑树和prim算法。 1. 支撑树 最小的连通图是树。 连通图G的某一无环连通子图T若覆盖G中所有的顶点&#xff0c;则称…

将克隆到本地的6.824项目上传到自己的github

前置知识见&#xff1a;把自己在本地完成的mit6.s081项目上传到自己的github仓库里_mit6.s081 lab上传-CSDN博客 先在github建立一个自己的仓库 由于github可以给自己的主分支改名了&#xff0c;我这次是勾选了创建README文件 在本地同样是建立一条remote分支 git remote add…

机器学习-- 如何清洗数据集

文章目录 引言&#xff1a;数据清洗的具体步骤数据清洗的具体方法和示例1. 处理缺失值2. 去除重复数据3. 修正数据格式4. 处理异常值5. 标准化和归一化6. 处理不一致的数据7. 转换数据类型8. 数据集成 总结 引言&#xff1a; 数据清洗是数据处理和分析的关键步骤&#xff0c;旨…

MLU370-M8 chattts-ui快速出击

目录 一、paas平台环境选择二、代码环境准备1.代码下载2.环境安装modelsopetransformersaccelerate 3.常规pip安装4.代码修改4.代码修改 三.算法启动 一、paas平台环境选择 驱动选择&#xff1a;5.10.22及以上 镜像选择&#xff1a;pytorch2.1 二、代码环境准备 1.代码下载…

macOS - 终端快捷键

本文转自 Mac 上“终端”中的键盘快捷键 https://support.apple.com/zh-cn/guide/terminal/trmlshtcts/mac 以下基于系统版本 macOS Sonoma 14 文章目录 Mac 上“终端”中的键盘快捷键1、使用“终端”窗口和标签页2、编辑命令行3、在“终端”窗口中选择和查找文本4、使用标记和…

UE5基础1-下载安装

目录 一.下载 二.安装 三.安装引擎 四.其他 简介: UE5&#xff08;Unreal Engine 5&#xff09;是一款功能极其强大的游戏引擎。 它具有以下显著特点&#xff1a; 先进的图形技术&#xff1a;能够呈现出令人惊叹的逼真视觉效果&#xff0c;包括高逼真的光影、材…

《Brave New Words 》3.4 最重要的学科领域

Part III Empowering the Next Innovators 第三部分 赋能下一代创新者 The Most Important Subject-Matter Domain to Master 最重要的学科领域 In the world of education, it’s crucial for developers to field-test their ideas. Essentially, it means taking our educat…

导数和微分

导数和微分 flyfish 本文主要论述其中的区别 导数是描述函数变化率的量&#xff0c;它表示函数在某点的瞬时变化速度和切线斜率。 微分是导数的一个线性近似&#xff0c;表示函数在某点处随着自变量变化的增量。 导数和微分在本质上都是研究函数变化的工具&#xff0c;但导数…

西门子学习笔记11 - PTO脉冲指令的使用

1、使用指令前的设置 1、打开一个脉冲发生器&#xff0c;并启用 2、选择使用PTO(脉冲A和方向B) 3、硬件设置输出 4、这样前期的准备工作就完成了 2、指令的使用 1、添加指令CTRL_PTO 2、配置如下 3、方向控制程序如下 4、最后进行测试即可

总结【GetHub的WebAPI,ASSET_ID】,【Linux的jq命令】(草稿版+实际操作)

目录 1.介绍一下github中的 asset_id 2. GitHub 的 asset_id相关操作 2.1.获取特定 repository 的 release 列表&#xff1a; 2.2.获取特定 release 中的 asset 列表&#xff0c;并找到 asset_id&#xff1a; 2.3.使用ASSET_ID获取资材 3.返回的 assets 的信息 是什么样样…

AI 大模型重点行业应用情况

1、AI 大模型重点行业应用情况总览 AI大模型将率先在互联网办公、金融等数字化程度较高的行业快速渗透&#xff0c;医疗、交通、 制造等行业的潜在渗透空间大。 2、AI 大模型在金融行业应用情况 金融行业的应用场景丰富&#xff0c;是最早进行数字化转型的机构&#xff0c;因此…