《动态顺序表》的实现

目录

前言:

认识线性表:

关于顺序表

实现动态顺序表:

顺序表的动态存储定义:

初始化顺序表:

顺序表的销毁:

尾插: 

判断是否需要扩容:

总代码:

 头插:

 打印顺序表:

尾删: 

头删: 

指定下标插入数据:

 指定下标删除:

查找元素下标:

总结:


前言:

从本文开始,我们就正式进入到了《数据结构》这门课程的入门学习,既然是入门,那我们就从较为基础和简单的部分“顺序表“开始我们的学习旅程。本文主要以模拟实现顺序表的增删查改等功能。该部分与我们之前所讲的《动态内存实现通讯录》较为相似,建议在学习此内容前,可以对《通讯录》这一部分进行复习和浏览:运用动态内存实现通讯录(增删查改+排序)-CSDN博客

认识线性表:

线性表是一种数据结构,是由n个具有相同数据类型的数据元素(节点)构成的有限序列。其中,n为线性表的长度,也称为表长。线性表中只有一个开始节点,也只有一个终止节点。线性表的两种常见实现方式是顺序存储和链式存储。

顺序存储是将线性表中的元素顺序存储在一块连续的存储空间(数组)中,通过元素在数组中的下标来访问元素。

链式存储是通过指针将线性表中的元素存储在离散的存储空间中。每个节点都包含元素信息和一个指向下一个节点的指针,通过遍历指针来访问元素。

线性表常见的操作有:插入、删除、查找、遍历等。其中查找操作主要包括按位置查找和按元素值查找。

线性表的应用非常广泛,常见的应用场景包括数组、链表、栈、队列、字符串等。

 

关于顺序表

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

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

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

静态顺序表只适用于确定知道需要存多少数据的场景。

静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小。

下面我们实现动态顺序表

实现动态顺序表:

顺序表的动态存储定义:

typedef int SLDataType;

typedef struct Seqlist
{
	SLDataType* a;//指向动态开辟的数组
	size_t sz;//有效数据个数
	size_t capacity;// 容量空间大小
}SL;

初始化顺序表:

void SLInit(SL* psl)
{
	assert(psl);
	psl->a = NULL;
	psl->capacity = 0;
	psl->sz = 0;
}

以上这一部分在我们的通讯录所讲的内容是一致的,如有不懂的还是可以再回顾回顾动态内存实现通讯录的部分,在这里我不做过多的赘述。

顺序表的销毁:

void SLDestory(SL* psl)
{
	assert(psl);
	free(psl->a);
	psl->a = NULL;
	psl->capacity = 0;
	psl->sz = 0;
}

尾插: 

对于尾插,顾名思义就是从尾巴插入元素,即在顺序表的数组中,在最后一个位置插入。

但这里我们要考虑一种情况,那就是那我们的预先开辟的空间满了的时候,要先进行扩容操作,再进行尾插,因此便有了以下的函数实现:

判断是否需要扩容:

void SLCheckCapacity(SL* psl)
{
	assert(psl);
	if (psl->sz == psl->capacity)
	{
		size_t newcapacity = (psl->capacity == 0) ? 4 : 2 * (psl->capacity);

		SLDataType* tmp = (SLDataType*)realloc(psl->a, sizeof(SLDataType)*newcapacity);
		if (tmp == NULL)
		{
			perror("SLCheckCapacity -> realloc");
			return;
		}

		psl->a = tmp;
		psl->capacity = newcapacity;
	}
}

对于以下代码,我们使用了三目操作符,如果我们一开始的空间capacity为0,那么我就给它一个初始空间4。

size_t newcapacity = (psl->capacity == 0) ? 4 : 2 * (psl->capacity);

 如果不是并且满了,我们就进行2倍扩容。

这里还要注意的是,realloc是可以对空指针进行扩容的,但是效果相当于malloc开辟空间!!

 当扩容操作结束后,就该进行真正的尾插操作。

总代码:

void SLPushBack(SL* psl, SLDataType x)
{
	assert(psl);
	SLCheckCapacity(psl);

	psl->a[psl->sz] = x;
	psl->sz++;
}

 头插:

对于头插我们则需要将a[0]之后的所有元素从后开始,依次往后挪一格,直到腾出a[0]的位置。

所以我们在此可以创建一个指针指向,顺序表最后一个元素,再往前遍历。

顺序表的最后一个元素的下标,熟练之后想都不用想,就是sz - 1!

记住结论!

数组最后一个元素的下标 = 当前元素个数 -1

所以就有了end = psl->sz - 1; 

所以总代码为:

void SLPushFront(SL* psl, SLDataType x)
{
	assert(psl);
	SLCheckCapacity(psl);

	size_t end = psl->sz - 1;
	while (end)
	{
		psl->a[end + 1] = psl->a[end];
		end--;
	}
	psl->a[0] = x;
	psl->sz++;
}

但是对于该算法,如果我们要插入n个数,那么该算法的时间复杂度就是O(N^2) 

因此不推荐头插。

而尾插的时间复杂度就直接O(1),所以我们尽量选择尾插而非头插! 

 打印顺序表:

该函数的实现比较简单,在这里我不做过多的赘述。

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

尾删: 

void SLPopBack(SL* psl)
{
	assert(psl);
	assert(psl->sz>0);
	psl->sz--;
}

对于该函数的实现,我们的重点就是要注意这个当前数据个数,即SZ的值。

如果我们当前本就没有值,即psl->sz == 0时。

若再进行减减操作,则会在下一次打印的时候出现漏打的现象。

因此我们在这里直接使用assert这种暴力的提醒方式,告诉你函数哪一行出现了错误:

这就是assert的作用!

头删: 

 对于头删,我们可以与刚刚所讲的头插进行联系,其实就是将第一个元素删除,即a[0]上面的元素被a[1]覆盖,而a[1]被a[2]覆盖,如此以来循环往复,就可以先创建个下标,然后循环遍历。

void SLPopFront(SL* psl)
{
	assert(psl);
	assert(psl->sz > 0);
	int begin = 1;
	while (begin < psl->sz)
	{
		psl->a[begin - 1] = psl->a[begin];
		begin++;
	}
	psl->sz--;
}

这里我们和尾删保持一致,先对当前数据个数进行assert断言判断。

指定下标插入数据:

既然是插入数据,那么我们也肯定是要创建指针来挪动数据,再将数据赋值到那个空位置。

代码实现如下:

void SLPushInsert(SL* psl, int pos, SLDataType x)
{
	assert(psl);
	assert(pos >= 0 && pos <= psl->sz);
	int end = psl->sz - 1;
	while (end >= pos)
	{
		psl->a[end + 1] = psl->a[end];
		end--;
	}
	psl->a[pos] = x;
	psl->sz++;
}

 指定下标删除:

 该函数实现于上述函数同理:

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

查找元素下标:

该函数可用于以上的指定元素删除和插入下标。

具体代码在之前也有讲解,在这里我也不做过多的赘述。

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

总结:

 以上我们实现了《顺序表》的初步,说实话该顺序表的实现与之前我们的对通讯录实现动态内存开辟的方式的思维较为类似,下来可以适当的复习通讯录的内容。

记住多练习多画图才可以明白!

“坐而言不如起而行”

Action speak louder than words!

以下是我的Gitee,里面有完整的代码,包括对菜单的实现!

Data structures amd algorithms: 关于数据结构和算法的代码 - Gitee.com

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

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

相关文章

C++——类和对象(中)完结

赋值运算符重载 运算符重载 C 为了增强代码的可读性引入了运算符重载 &#xff0c; 运算符重载是具有特殊函数名的函数 &#xff0c;也具有其 返回值类型&#xff0c;函数名字以及参数列表&#xff0c;其返回值类型与参数列表与普通的函数类似。 函数名字为&#xff1a;关键…

父子进程之间的等待(wait和waitpid的介绍+原理),status的介绍+恢复退出码(位运算+宏),非阻塞等待(宏),signal查看

目录 父子进程之间的等待 介绍 为什么要有等待 内存泄漏 如何等待 介绍 pid_t wait (int* status) 介绍 status指针 示例 ​编辑 pid_t waitpid (pid_t pid,int* status,int options) pid options WNOHANG -- 非阻塞等待 示例 status 查看status status问题 …

Mybatis与Mybatis-Plus(注解与Xml)(单表与多表)

准备工作 这里我们准备了两个与数据库表对应的实体类&#xff0c;stu为学生表&#xff0c;cls为班级表 类属性上的注解如 TableId等 为Mybatis-Plus的注解&#xff0c;使用mybatis会无视掉这些注解 在Stu 类的最后一个属性我们定义了Cls实体类的对象&#xff0c;对于单表查询&…

EASYX输出文字

在EASYX中绘制出字符串和字符 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <easyx.h> #include <iostream> #include <math.h> #include <stdlib.h> #include <conio.h> #include <time.h> #define PI 3.14、 //…

Windows 下编译 TensorFlow 2.9.1 CC库

参考 Intel 的 tensorflow 编译指导&#xff0c;不过项目还是可以用 TF原本的&#xff0c;不是一定要选择Intel 的TF版本。 安装 MSVC 2019 安装 Intel OneDNN OneMKL 似乎也可以不安装 ( & ) https://www.intel.cn/content/www/cn/zh/developer/articles/tool/one…

算法随想录算法训练营第四十七天| 647. 回文子串 516.最长回文子序列

647. 回文子串 题目&#xff1a;给你一个字符串 s &#xff0c;请你统计并返回这个字符串中 回文子串 的数目。回文字符串 是正着读和倒过来读一样的字符串。子字符串 是字符串中的由连续字符组成的一个序列。具有不同开始位置或结束位置的子串&#xff0c;即使是由相同的字…

开发知识点-PHP从小白到拍簧片

从小白到拍簧片 位异或运算&#xff08;^ &#xff09;引用符号(&)strlen() 函数base64_encode预定义 $_POST 变量session_start($array);操作符php 命令set_time_limit(7200)isset()PHP 命名空间(namespace)new 实例化类extends 继承 一个类使用另一个类方法error_reporti…

【C语法学习】16 - fclose()函数

文章目录 1 函数原型2 参数3 返回值4 示例 1 函数原型 fclose()&#xff1a;关闭已打开的文件&#xff0c;并刷新缓冲区&#xff0c;函数原型如下&#xff1a; int fclose(FILE *stream);2 参数 fclose()函数只有一个参数stream&#xff1a; 参数stream是一个指向FILE类型结…

Daily neaty和希亦内衣洗衣机哪款好,高性价比内衣洗衣机测评

现在市面最火的小家电莫过于是内衣洗衣机&#xff0c;那么它是否真的好用还是只是智商税呢&#xff1f;但关于内衣洗衣机&#xff0c;很多小伙伴都会选入手来释放自己的双手的&#xff0c;现在内衣洗衣机品牌众多&#xff0c;而且Daily neaty和希亦CEYEE-ACE这两个大品牌会被许…

【漏洞复现】Apache_HTTPD_换行解析漏洞(CVE-2017-15715)

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞扫描3、漏洞验证 1.5、深度利用GetShell 1.6、修复建议 说明内容漏洞编号CVE-2017-15715漏洞名称Ap…

京东数据平台:2023年9月京东智能家居行业数据分析

鲸参谋监测的京东平台9月份智能家居市场销售数据已出炉&#xff01; 9月份&#xff0c;智能家居市场销售额有小幅上涨。根据鲸参谋电商数据分析平台的相关数据显示&#xff0c;今年9月&#xff0c;京东平台智能家居的销量为37万&#xff0c;销售额将近8300万&#xff0c;同比增…

如何理解所谓的【指令执行速度】

公式&#xff1a; 指令执行速度 主频/平均CPI 先不看主频&#xff0c;如下图&#xff0c;假设一秒钟能有4个正弦波&#xff0c;那就说明频率是4。 而计算机很厉害&#xff0c;一秒能有很多个正弦波 把一个正弦波&#xff0c;看做一个时钟周期 则主频表示&#xff0c;计算机…

g.Grafana之Gauge的图形说明

直接上操作截图 1. 创建一个新的Dashboard 2.为Dashboard创建变量 【General】下的Name与Label的名称自定义 【Query options】 下的Group可以填写Zabbix内的所有组/.*/ , 然后通过Regex正则过滤需要的组名 3.设置Dashboard的图形 我使用文字来描述下这个图 1.我们在dash…

Java数组小练习求出数组中的最大值

加油&#xff0c;新时代打工人&#xff01; Java基础八之数组的定义和获取元素 package demo;/*** author wenhao* date 2023/11/04 10:47* description 数组练习*/ public class ArrDemo {public static void main(String[] args) {//求一个数组中的最大值int [] arr {66,12…

YOLOv7独家原创改进:新颖自研设计的BSAM注意力,基于CBAM升级

💡💡💡本文全网首发独家改进:提出新颖的注意力BSAM(BiLevel Spatial Attention Module),创新度极佳,适合科研创新,效果秒杀CBAM,Channel Attention+Spartial Attention升级为新颖的 BiLevel Attention+Spartial Attention 1)作为注意力BSAM使用; 推荐指数:…

clusterprolifer go kegg msigdbr 富集分析应该使用哪个数据集,GO?KEGG?Hallmark?

关注微信&#xff1a;生信小博士 5 Overview of enrichment analysis Chapter 5 Overview of enrichment analysis | Biomedical Knowledge Mining using GOSemSim and clusterProfiler 5.1.2 Gene Ontology (GO) Gene Ontology defines concepts/classes used to describ…

氮化镓功率放大器长期记忆效应的补偿

标题&#xff1a;Compensation of Long-Term Memory Effects on GaN HEMT-Based Power Amplifiers 来源&#xff1a;IEEE TRANSACTIONS ON MICROWAVE THEORY AND TECHNIQUES DPD&#xff1a;数字预失真&#xff08;Digital Pre-Distortion&#xff09;RF PA&#xff1a;射频功…

数据结构(超详细讲解!!)第十九节 块链串及串的应用

1.定义 由于串也是一种线性表&#xff0c;因此也可以采用链式存储。由于串的特殊性&#xff08;每个元素只有一个字符&#xff09;&#xff0c;在具体实现时&#xff0c;每个结点既可以存放一个字符&#xff0c;也可以存放多个字符。每个结点称为块&#xff0c;整个链表称为块链…

python使用requests+excel进行接口自动化测试

在当今的互联网时代中&#xff0c;接口自动化测试越来越成为软件测试的重要组成部分。Python是一种简单易学&#xff0c;高效且可扩展的语言&#xff0c;自然而然地成为了开发人员的首选开发语言。而requests和xlwt这两个常用的Python标准库&#xff0c;能够帮助我们轻松地开发…

JavaEE平台技术——预备知识(Web、Sevlet、Tomcat)

JavaEE平台技术——预备知识&#xff08;Web、Sevlet、Tomcat&#xff09; 1. Web基础知识2. Servlet3. Tomcat并发原理 1. Web基础知识 &#x1f192;&#x1f192;上个CSDN我们讲的是JavaEE的这个渊源&#xff0c;实际上讲了两个小时的历史课&#xff0c;给大家梳理了一下&a…