数据结构 ——— C语言实现动态顺序表

news2024/10/1 17:40:58

目录

顺序表的概念

顺序表的结构(静态顺序表和动态顺序表)

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

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

为什么选择实现动态顺序表

静态顺序表的缺点:

动态顺序表的优点:

实现动态顺序表的准备工作

实现动态顺序表

1. 初始化动态顺序表

 2. 释放动态顺序表

3. 打印动态顺序表的有效数据

4. 扩容

4. 在顺序表的尾部插入数据

5. 在顺序表的尾部删除数据

6. 在顺序表头部插入数据

7. 在顺序表头部删除数据

8. 在顺序表中间位置插入数据

9. 查找顺序表中的指定数据

10. 在顺序表中间位置删除数据

11. 在顺序表中修改指定的数据 


顺序表的概念

顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,顺序表的本质就是数组,所以一般情况下采用数组存储,在数组上完成数据的增删查改


顺序表的结构(静态顺序表和动态顺序表)

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

静态顺序表结构代码演示:

#define N 10

// 数据的类型
typedef int SLDataType;

typedef struct SeqList
{
	SLDataType array[N]; //固定长度的数组
	size_t size; //有效数据的个数
}SeqList;

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

动态顺序表结构代码演示:

// 数据的类型
typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* array; //指向动态开辟的数组的指针
	size_t size; //有效数据个数
	size_t capicity; //空间容量大小
}SeqList;

为什么选择实现动态顺序表

静态顺序表的缺点:

空间大小是固定的,当有效数据 等于 数组的最大容量的时候就不能存储数据了

且存储的数据个数是未知的,所以数组空间的大小太小了不够用,但是太大了又浪费

动态顺序表的优点:

当当前有效数据 等于 数组最大容量的时候可以使用 malloc 扩容,不用担心数组会存储不了数据


实现动态顺序表的准备工作

创建3个文件

test.c 文件:用来测试增删查改功能是否完善

SeqList.h 文件:用来声明动态顺序表的结构以及声明增删查改函数 

SeqList.c 文件:用来实现动态顺序表的增删查改及功能函数


实现动态顺序表

1. 初始化动态顺序表

void SLInit(SeqList* psl)
{
	// 动态开辟 4 个 SLDataType 类型的空间
	psl->array = (SLDataType*)malloc(sizeof(SLDataType) * 4);

	// 判断是否开辟成功
	if (psl->array == NULL)
	{
		perror("malloc fail");
		return;
	}

	psl->capicity = 4;
	psl->size = 0;
}

SLDataType 是 typedef 而来的:

typedef int SLDataType;

是用来定义数组元素的类型,这样做的好处是只需要修改这一处,就能改变整个数组的类型

测试代码:


 2. 释放动态顺序表

void SLDestroy(SeqList* psl)
{
	// 释放动态开辟的空间
	free(psl->array);

	// 置空和置零
	psl->array = NULL;
	psl->capicity = 0;
	psl->size = 0;
}

测试代码:


3. 打印动态顺序表的有效数据

void SLPrint(SeqList* psl)
{
	// 当前动态数组中没有存储有效数据时
	if (psl->size == 0)
	{
		printf("无有效数据\n");
		return;
	}

	for (int i = 0; i < psl->size; i++)
	{
		printf("%d ", psl->array[i]);
	}
	printf("\n");
}

打印数据会出现两种情况,有数据和无数据:

无数据时:可以提醒用户当前动态数组中没有有效数据

有数据时:直接从 0 遍历到 size 当作下标再打印即可 


4. 扩容

void BuyCapicity(SeqList* psl)
{
	if (psl->capicity == psl->size)
	{
		// 利用三目操作符,防止用户不使用初始化函数,直接扩容的情况
		psl->capicity = (psl->capicity == 0) ? 4 : psl->capicity * 2;

		SLDataType* tmp = (SLDataType*)realloc(psl->array, sizeof(SLDataType) * psl->capicity);

		// 判断是否扩容成功
		if (tmp == NULL)
		{
			perror("realloc fail");
			return;
		}

		// 确定扩容成功再赋值
		psl->array = tmp;
		printf("成功扩容,当前容量:%d\n", psl->capicity);
	}
	else
	{
		return;
	}
}

扩容时,先不要使用 pls->array 原指针进行扩容,要先创建一个临时指针,扩容成功后再赋值给原指针接管,这样做的好处是以免 realloc 函数扩容失败,扩容失败就会返回 NULL,当 pls->array 赋值为 NULL,那么就查看不到之前的有效数据


4. 在顺序表的尾部插入数据

void SLPushBack(SeqList* psl, SLDataType x)
{
	// 尾插前先判断是否需要扩容
	BuyCapicity(psl);

	psl->array[psl->size] = x;
	psl->size++;
}

当前有效数据个数 psl->size 就是要尾插数据的下标

测试代码:


5. 在顺序表的尾部删除数据

void SLPopBack(SeqList* psl)
{
	// 当前没有有效数据或者有效数据以被删完时
	if (psl->size == 0)
	{
		printf("无数据可删除\n");
		return;
	}

	psl->size--;
}

直接把 psl->size 递减 1 即可 

测试代码:


6. 在顺序表头部插入数据

void SLPushFront(SeqList* psl, SLDataType x)
{
	// 头插前先判断是否需要扩容
	BuyCapicity(psl);

	// 当前有效数据整体向后挪动一个元素
	for (int i = psl->size; i > 0; i--)
	{
		psl->array[i] = psl->array[i - 1];
	}

	psl->array[0] = x;
	psl->size++;
}

测试代码:


7. 在顺序表头部删除数据

void SLPopFront(SeqList* psl)
{
	// 当前没有有效数据或者有效数据以被删完时
	if (psl->size == 0)
	{
		printf("无数据可删除\n");
		return;
	}

	// 从第二个元素开始,依次向前覆盖
	for (int i = 0; i < psl->size - 1; i++)
	{
		psl->array[i] = psl->array[i + 1];
	}

	psl->size--;
}

 测试代码:


8. 在顺序表中间位置插入数据

void SLInsert(SeqList* psl, int pos, SLDataType x)
{
	// 中插前先判断是否需要扩容
	BuyCapicity(psl);

	// 判断 pos 的合法性
	if (pos < 1 || pos > psl->size)
	{
		printf("非法插入\n");
		return;
	}

	// 从pos位置往后的有效元素整体向后挪动
	for (size_t i = psl->size; i > pos - 1; i--)
	{
		psl->array[i] = psl->array[i - 1];
	}

	psl->array[pos - 1] = x;
	psl->size++;
}

我是以用户的角度设计的, pos 位置是元素个数位置,大家可以自行设计不同的 pos 位置,可以设计成 pos 位置是元素下标的位置

测试代码:


9. 查找顺序表中的指定数据

int SLFind(SeqList* psl, SLDataType x)
{
	for (int i = 0; i < psl->size; i++)
	{
		if (psl->array[i] == x)
		{
			// 找到了返回下标
			return i;
		}
	}

	return -1;
}

找到了指定的元素就返回元素的下标,没有找到就返回 -1 ,因为下标可不能是 -1


10. 在顺序表中间位置删除数据

void SLErase(SeqList* psl, SLDataType x)
{
	int ret = SLFind(psl, x);

	// 判断是否找到指定元素
	if (ret != -1)
	{
		// 向前覆盖
		for (int i = ret; i < psl->size - 1; i++)
		{
			psl->array[i] = psl->array[i + 1];
		}

		psl->size--;
	}
	else
	{
		printf("没有找到指定元素\n");
	}
}

配合 SLFind 函数使用,先使用 SLFind 函数找到要删除的值,并通过 SLFind 返回的下标判断并删除

测试代码:


11. 在顺序表中修改指定的数据 

void SLModity(SeqList* psl, SLDataType x, SLDataType input)
{
	int ret = SLFind(psl, x);

	// 判断是否找到指定元素
	if (ret != -1)
	{
		psl->array[ret] = input;
	}
	else
	{
		printf("没有找到指定元素\n");
	}
}

x 为顺序表中要修改的有效数据,input 是修改的值

测试代码:

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

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

相关文章

读构建可扩展分布式系统:方法与实践15可扩展系统的基本要素

1. 可扩展系统的基本要素 1.1. 分布式系统在本质上就是复杂的&#xff0c;你必须考虑多种故障模式&#xff0c;并设计应对所有可能发生的情况的处理方式 1.2. 大规模应用程序需要协调大量的硬件和软件组件&#xff0c;共同实现低延迟和高吞吐量的能力 1.3. 面临的挑战是将所…

入门Django

Django Django 简介URL组成部分详解第一个Django项目创建一个Django项目运行Django项目项目结构介绍project和app的关系 URL与视图函数的映射URL的两种传参方式在URL中携带参数 path函数url路由模块化url反转 Django 简介 Django 是一个高级的 Python Web 框架&#xff0c;用于…

书生白嫖A100活动之——OpenCompass

内容来源&#xff1a;Tutorial/opencompass/readme.md at camp2 InternLM/Tutorial GitHub 概览 在 OpenCompass 中评估一个模型通常包括以下几个阶段&#xff1a;配置 -> 推理 -> 评估 -> 可视化。 配置&#xff1a;这是整个工作流的起点。您需要配置整个评估过…

HTML中的表单(超详细)

一、表单 1.语法 <!-- action&#xff1a;提交的地方 method&#xff1a;提交的方式&#xff08;get会显示&#xff0c;post不会&#xff09; --> <form action"#" method"get"><p>名字&#xff1a;<input name"name" ty…

【Geoserver使用】SRS处理选项

文章目录 前言一、Geoserver的三种SRS处理二、对Bounding Boxes计算的影响总结 前言 今天来看看Geoserver中发布图层时的坐标参考处理这一项。根据Geoserver官方文档&#xff0c;坐标参考系统 (CRS) 定义了地理参考空间数据与地球表面实际位置的关系。CRS 是更通用的模型&…

3. 轴指令(omron 机器自动化控制器)——>MC_MoveFeed

机器自动化控制器——第三章 轴指令 8 MC_MoveFeed变量▶输入变量▶输出变量▶输入输出变量 功能说明▶指令详情▶时序图▶重启运动指令▶多重启动运动指令▶异常 示例程序▶参数设定▶动作示例▶梯形图▶结构文本(ST) MC_MoveFeed 指定自外部输入的中断输入发生位置起的移动距…

2024免费录屏软件的宝藏功能与实用技巧

在手机上操作很多时候为了记录方便都直接截图或者录屏&#xff0c;其实电脑也一样。现在面向电脑的录屏工具纷繁复杂&#xff0c;很容易让我们挑花了眼。今天这篇文章我将介绍几款免费的录屏软件为大家提供参考。 1.福昕录屏大师 链接达达&#xff1a;www.foxitsoftware.cn/R…

深入探索 RUM 与全链路追踪:优化数字体验的利器

作者&#xff1a;梅光辉&#xff08;重彦&#xff09; 背景介绍 随着可观测技术的持续演进&#xff0c;多数企业已广泛采用 APM、Tracing 及 Logging 解决方案&#xff0c;以此强化业务监控能力&#xff0c;尤其在互联网行业&#xff0c;产品的体验直接关系着用户的口碑&…

使用Crawler实例进行网页内容抓取

网页内容抓取的背景 随着互联网的快速发展&#xff0c;网页上的信息量日益庞大。如何从海量的网页中快速、准确地抓取所需信息&#xff0c;成为了一个技术挑战。网页内容抓取技术通过自动化的方式&#xff0c;模拟用户浏览网页的过程&#xff0c;获取网页上的文本、图片、链接…

mybatisplus介绍以及使用(上)

目录 一、概念 1、什么是mybatisplus 2、为什么要使用mybatisplus 二、mybatisplus的使用 1、安装 2、常用注解 3、条件构造器 一、概念 1、什么是mybatisplus MyBatis-Plus&#xff08;简称MP&#xff09;是一个基于MyBatis的增强框架&#xff0c;旨在简化开发、提高…

学习C语言(20)

在这段没有更新的时间作者大一开学了&#xff0c;军训期间一直比较忙没时间学习&#xff0c;9月23号结束了为期十四天的军训&#xff0c;今天开始重新更学习C语言的博客 整理今天的学习内容 1.浮点数在内存中的储存 浮点数包括float&#xff0c;double&#xff0c;long doub…

vue实现左侧数据拖拽到右侧区域,且左侧数据保留且左侧数据不能互相拖拽改变顺序

一、案例效果 二、案例代码 封装左侧抽屉 DrawerSearch.vue <template><div><mtd-form :model"formDrawerSearch" ref"formCustom" inline><mtd-form-item><mtd-inputtype"text"v-model"formDrawerSearch.hos…

美团一面:给定两棵二叉树 `A` 和 `B`,判断 `B` 是否是 `A` 的子结构?

目录标题 问题描述思路分析代码解释详细步骤复杂度分析 问题描述 给定两棵二叉树 A 和 B&#xff0c;判断 B 是否是 A 的子结构。所谓子结构是指 B 中任意节点在 A 中存在相同的结构和节点值。 例子1&#xff1a; 输入&#xff1a;tree1 [1,7,5], tree2 [6,1] 输出&#…

LeaferJS 动画、状态、过渡、游戏框架

LeaferJS 现阶段依然专注于绘图、交互和图形编辑场景。我们引入游戏场景&#xff0c;只是希望让 LeaferJS 被更多有需要的人看到&#xff0c;以充分发挥它的价值 LeaferJS 为你带来了全新的游戏、动画、状态和过渡功能&#xff0c;助你实现那些年少时的游戏梦想。我们引入了丰富…

NVIDIA TAO 工具套件5.3.0学习介绍及操作-01

什么是 NVIDIA TAO 工具套件&#xff1f; NVIDIA TAO 工具套件基于 TensorFlow 和 PyTorch 构建&#xff0c;是 NVIDIA TAO 框架的低代码版本&#xff0c;通过抽象出 AI/深度学习框架的复杂性来加速模型训练过程。TAO 工具套件让您利用迁移学习的强大功能和自己的数据对预训练 …

Remotion:使用前端技术开发视频

前言 最近做文章突然想到很多文章其实也可以用视频的方式来展现&#xff0c;以现在短视频的火爆程度&#xff0c;肯定能让更多的人看到。 恰巧最近看了很多关于动画的前端 js 库&#xff0c;那如果将这些动画帧连续起来&#xff0c;岂不是就成了一个视频吗&#xff1f; 而且…

集成Elasticsearch到django restful

文章目录 集成ES到django restful服务端项目安装haystack基本使用安装配置索引模型ORM模型中新增discount_json字段方法全文索引字段模板 索引序列化器全文搜索的索引视图路由手动构建es索引 集成ES到django restful服务端项目 如果直接在Django项目直接编写代码作为ElasticSe…

YOLOv5白皮书-第Y2周:训练自己的数据集(云jupyter运行版 )

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营](小团体&#xff5e;第八波) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊](K同学啊-CSDN博客)** 目录 前言 一、.xml文件里保存的是什么 二、准备好自己的数据 三、创建split_tr…

spring boot 3 + 虚拟线程 + MDC traceId

虚拟线程&#xff08;Virtual Thread&#xff09;也称协程或纤程&#xff0c;是一种轻量级的线程实现&#xff0c;与传统的线程以及操作系统级别的线程&#xff08;也称为平台线程&#xff09;相比&#xff0c;它的创建开销更小、资源利用率更高&#xff0c;是 Java 并发编程领…

ChatGPT-4模型镜像站对比和【软件开发人员】提示词

AI如今很强大&#xff0c;聊聊天、写论文、搞翻译、写代码、写文案、审合同等等&#xff0c;ChatGPT 真是无所不能~ 作为一款出色的大语言模型&#xff0c;ChatGPT 实现了人类般的对话交流&#xff0c;最主要是能根据上下文进行互动。 接下来&#xff0c;我将介绍 ChatGPT 在…