顺序表详解 —— 初始化、销毁、打印、增加、删除、查找、修改

2023-11-16

顺序表介绍

顺序表是在计算机内存中以数组的形式保存的线性表,线性表的顺序存储是指用一组地址连续的存储单元依次存储线性表中的各个元素、使得线性表中在逻辑结构上相邻的数据元素存储在相邻的物理存储单元中,即通过数据元素物理存储的相邻关系来反映数据元素之间逻辑上的相邻关系,采用顺序存储结构的线性表通常称为顺序表。顺序表是将表中的结点依次存放在计算机内存中一组地址连续的存储单元中

在这里,我们可能会有些迷惑,顺序表和普通的数组有什么区别呢?
顺序表和普通数组的区别主要有以下两点:

1.顺序表的长度可以动态增长,普通数组的长度是固定的。
2.顺序表要求插入的数据在内存中是连续的,普通数组的数据存放可以不连续。

初始化顺序表

首先,我们要创建一个顺序表类型,该顺序表类型包括了顺序表的起始位置、记录顺序表内已有元素个数的计数器(size),以及记录当前顺序表的容量的变量(capacity)。

typedef int SLDataType;//本篇博客以存放整型数据为例

typedef struct SeqList
{
	SLDataType* a;//声明了一个指向顺序表的指针,姑且称它为“顺序表指针”
	int size;//记录当前顺序表内元素个数
	int capacity;//记录当前顺序表的最大容量
}SeqList;

然后,我们需要一个初始化函数,对顺序表进行初始化。

//初始化顺序表
void SeqListInit(SeqList* ps)
{
	assert(ps);
	ps->a = NULL;//刚开始时顺序表为空,顺序表指针为NULL
	ps->size = 0;//起始时元素个数为0
	ps->capacity = 0;//容量为0
}

销毁顺序表

因为顺序表所用的内存空间是动态开辟在堆区的,所以我们在使用完后需要及时对其进行释放,避免造成内存泄漏

//销毁顺序表
void SeqListDestory(SeqList* ps)
{
	assert(ps);
	free(ps->a);//释放顺序表指针指向的空间
	ps->a = NULL;//及时置空
	ps->size = 0;//元素个数置0
	ps->capacity = 0;//容量置0
}

若需要对数据进行保存,可以使用文件操作函数将数据保存到一个文件中,下次使用顺序表的时候先读取文件数据即可。

打印顺序表

打印就比较简单了,依次循环打印size个元素即可。

//打印顺序表
void SeqListPrint(SeqList* ps)
{
	assert(ps);
	int i = 0;
	//循环打印顺序表指针指向的数据
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

增加数据

仔细想想,我们每次需要增加数据的时候,首先都应该先检查顺序表内元素个数是否已达顺序表容量上限。若已达上限,那么我们就需要先对顺序表进行扩容,然后才能增加数据。

//检查顺序表容量是否已满,若已满,则增容
void SeqCheckCapacity(SeqList* ps)
{
	if (ps->size == ps->capacity)//满了,需要增容
	{
		//判断顺序表容量是否为0,若为0,则先开辟用于存放4个元素的空间大小,若不为0,则扩容为原来容量的两倍
		int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* newA = realloc(ps->a, newcapacity*sizeof(SLDataType));
		if (newA == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}
		ps->a = newA;//开辟成功,将顺序表指针更新
		ps->capacity = newcapacity;//容量更新
	}
}

注意:若传入realloc的指针为空指针(NULL),则realloc函数的作用相当于malloc函数。

头插

要想在顺序表的表头插入数据,那么就需要先将顺序表原有的数据从后往前依次向后挪动一位,最后再将数据插入表头。

//头插
void SeqListPushFront(SeqList* ps, SLDataType x)
{
	assert(ps);
	SeqCheckCapacity(ps);//检查容量
	int i = 0;
	for (i = ps->size; i > 0; i--)//将数据从后往前依次向后挪
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[0] = x;
	ps->size++;//顺序表元素个数加一
}

注意:挪动数据的时候应从后向前依次挪动,若从前向后挪动,会导致后一个数据被覆盖。

尾插

尾插相对于头插就比较简单了,直接在表尾插入数据即可。

//尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{
	assert(ps);
	SeqCheckCapacity(ps);//检查容量
	ps->a[ps->size] = x;
	ps->size++;//顺序表元素个数加一
}

指定下标位置插入

要做到在指定下标位置插入数据,首先我们需要得到一个下标位置,然后从该下标位置开始(包括该位置),其后的数据从后往前依次向后挪动一位,最后将数据插入到该下标位置。

//指定下标位置插入
void SeqListInsert(SeqList* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);//检查输入下标的合法性
	SeqCheckCapacity(ps);//检查容量
	int i = 0;
	for (i = ps->size; i > pos; i--)//从pos下标位置开始,其后的数据从后往前依次向后挪
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[pos] = x;
	ps->size++;//顺序表元素个数加一
}

我们可以发现,头插和尾插实际上就是在下标为0的位置和下标为ps->size的位置插入数据,也就意味着我们可以统一使用该函数来实现头插和尾插。

//头插
void SeqListPushFront(SeqList* ps, SLDataType x)
{
	SeqListInsert(ps, 0, x);//在下标为0的位置插入数据
}
//尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{
	SeqListInsert(ps, ps->size, x);//在下标为ps->size的位置插入数据
}

删除数据

删除数据,其实可以理解为:从某个位置开始,数据依次向前覆盖。这样一来,该位置的数据就相当于删除了。

头删

要删除表头的数据,我们可以从下标为1的位置开始,依次将数据向前覆盖即可。

//头删
void SeqListPopFront(SeqList* ps)
{
	assert(ps);
	assert(ps->size > 0);//保证顺序表不为空
	int i = 0;
	for (i = 0; i < ps->size - 1; i++)//将数据从前往后依次向前覆盖
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;//顺序表元素个数减一
}

注意:数据覆盖的时候应从前向后依次覆盖,若从后向前覆盖,会导致前一个数据被覆盖。

尾删

尾删就更简单了,直接将顺序表的元素个数减一即可。

//尾删
void SeqListPopBack(SeqList* ps)
{
	assert(ps);
	assert(ps->size > 0);//保证顺序表不为空
	ps->size--;//顺序表元素个数减一
}

指定下标位置删除

要删除指定下标位置的数据,我们只需要从下标位置开始,其后的数据从前向后依次覆盖即可。

//指定下标位置删除
void SeqListErase(SeqList* ps, int pos)
{
	assert(ps);
	assert(ps->size > 0);//保证顺序表不为空
	assert(pos >= 0 && pos < ps->size);
	int i = 0;
	for (i = pos; i < ps->size - 1; i++)//从pos下标位置开始,其后的数据从前往后依次向前覆盖
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->size--;//顺序表元素个数减一
}

同样的道理,头删和尾删实际上也就是删除下标为0的位置和下标为ps->size - 1的位置的数据,也就意味着我们可以统一使用该函数来实现头删和尾删。

//头删
void SeqListPopFront(SeqList* ps)
{
	SeqListErase(ps, 0);//删除下标为0的位置的数据
}
//尾删
void SeqListPopBack(SeqList* ps)
{
	SeqListErase(ps, ps->size - 1);//删除下标为ps->size - 1的位置的数据
}

查找数据

查找数据也相对简单,直接遍历一次顺序表即可,若找到了目标数据,则停止遍历,并返回该数据的下标,否则返回-1。

//查找元素,若有,返回下标,否则返回-1
int SeqListFind(SeqList* ps, SLDataType x)
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; i++)//遍历顺序表进行查找
	{
		if (ps->a[i] == x)
			return i;//找到该数据,返回下标
	}
	return -1;//未找到,返回-1
}

修改数据

修改数据,就直接对该位置的数据进行再次赋值即可。

//修改指定下标位置元素
void SeqListModify(SeqList* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);//检查输入下标的合法性
	ps->a[pos] = x;//修改数据
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

顺序表详解 —— 初始化、销毁、打印、增加、删除、查找、修改 的相关文章

  • Spark性能调优之Shuffle调优

    Spark性能调优之Shuffle调优 Spark底层shuffle的传输方式是使用netty传输 netty在进行网络传输的过程会申请堆外内存 netty是零拷贝 所以使用了堆外内存 shuffle过程中常出现的问题 常见问题一 redu
  • 服务器物理结构,物理 I/O 体系结构

    物理 I O 体系结构 与以前发行版的 M 系列服务器相比 这些服务器的物理 I O 体系结构发生了变化 使用了不同的名称 并且 CPU 不再拥有 PCIe 结构 I O 术语 用于描述 I O 体系结构的术语发生了如下变化 根联合体 在
  • React Effects(副作用)

    我们在之前提到过 React 组件在渲染过程中不应该有可观察到的副作用 但是有些时候副作用确实必要的 我们也许需要进行管理 focus 状态 用 canvas 画图 订阅数据源等操作 在 React 中 这些都可以通过声明 effect 来

随机推荐

  • ag-grid 自带css样式记录

    本篇文章是打算自己用于记录ag grid自身的css样式的记录和功能 1 ag header group cell with group 作用 多表头 前几层 最后一行表头除外 表头样式的设置 ag header group cell wi
  • pg备份数据库

    原文 http www weijingbiji com 1975 PostgreSQL备份工具pg dump和pg dumpall PostgreSQL 数据库 作者 viking PostgreSQL使用 pg dump 和 pg dum
  • [知识图谱实战篇] 七.HTML+D3实现关系图谱搜索功能

    前面作者讲解了很多知识图谱原理知识 包括知识图谱相关技术 Neo4j绘制关系图谱等 但仍缺少一个系统全面的实例 为了加深自己对知识图谱构建的认识 为后续创建贵州旅游知识图谱打下基础 作者深入学习了张宏伦老师的网易云课程 星球系列电影 并结合
  • Python利用demoji库删除文档中的表情符号

    在进行数据清洗时 往往需要删除文档中的出现的表情符号 因为他们无法被读取 借助demoji库 可以非常简单地完成这项工作 关于demoji 库的文档 可以访问demoji PyPI 首先 需要在环境中利用pip install安装demoj
  • 可拖拽的easyui treegrid

    引用 JQuery EasyUI TreeGrid控件的使用 支持拖拽与禁止拖拽 演示
  • 实际的机械臂控制(9)Moveit单独控制机械臂末端在XYZ三个轴的平移和旋转(基于python)

    0 序言 在moveit中 控制机械臂的末端执行器运动的API有两个 分别是 shift pose target set pose target 第一个API shift pose target 其实这个函数在旋转角度这块并不会得到让大家满
  • flutter 中stack 控件的 大小是如何确定的

    stack 控件 stack 是我们在flutter中常用到的控件 然而stack的大小是如何确定的是一个值得探究的问题 自己在网上也进行了搜索 但是总是不能解释自己遇到的新情况 所以我这里就根据目前的经验对stack大小是如何确定的进行一
  • 泰森多边形(Voronoi图)生成算法

    一 文档目的 本文描述了在geomodel模块中 生成泰森多边形所使用的算法 二 概述 GIS和地理分析中经常采用泰森多边形进行快速插值 和分析地理实体的影响区域 是解决邻接度问题的又一常用工具 荷兰气候学家A H Thiessen提出了一
  • 软件构架、架构和框架的区别

    软件框架 Software Framework 介绍 面向某领域 包括业务领域 如ERP 和计算领域 如GUI 的 可复用的 半成品 软件 它实现了该领域的共性部分 并提供一系列定义良好的可变点以保证灵活性和可扩展性 可以说 软件框架是领域
  • 重新学javaweb---ServletContext

    WEB容器在启动时 它会为每个WEB应用程序都创建一个对应的ServletContext对象 它代表当前web应用 这个对象创建出来之后就一直在内存中驻留 代表当前的web应用 它可以通过我们上一篇介绍的ServletConfig对象获取
  • arm-linux-gcc char与signed char和unsigned char

    1 三者关系 1 ANSI C 提供了3种字符类型 分别是char signed char unsigned char 而不是像short int一样只有两种 int默认就是unsigned int 2 三者都占1个字节 3 signed
  • 不规则语法命名数据框tibble

    本题来自 R数据科学 第7章使用tibble实现简单数据框 4 在以下的数据框中练习如何引用不符合语法规则的变量名 a 提取名称为 1 的变量 b 绘制表示变量 1 和变量 2 关系的散点图 c 创建一个名称为 3 的新列 其值为列 2 除
  • make_heap(), pop_heap(), push_heap()用法

    对make heap pop heap push heap 的用法做个总结 make heap 生成堆 他有两个参数 也可以有三个参数 前两个参数是指向开始元素的迭代器和指向结束元素的下一个元素的迭代器 第三个参数是可选的 可以用伪函数le
  • Python爬虫——8-1.scrapy深度爬取案例—百思不得姐

    对于scrapy框架的使用 爬取数据 多次运行命令行也是比较头疼和麻烦的 这里建议Windows R键输入cmd进入命令行 切入至项目所在目录后执行scrapy shell url 命令 可以很直观的检测程序是否出错 如xpath匹配路径是
  • 蓝桥杯经验分享

    作为已经入码坑的一员 在开始接触的时候一窍不通 老师讲完之后自己再写一遍都写不出来的那种 很是沮丧 失落 后来到了大二 逐渐的找到了感觉 在学习了诸如C C java python之后 感觉诸多编程语言殊途同归 编者观点 学习编程语言入手最
  • IDEA文件右键创建New没有Create New Servlet的解决办法

    Author codepig16 interesting wtsb7 1 问题描述 创建了一个Javaweb项目但是在src中右键创建中 没有Servlet选项 如下图所示 2 解决方案 解决方案分为三步 笔者本人是在第三步有问题 估计大部
  • Qt中左侧列表与右侧窗口关联

    左边列表选项与右边窗体关联 QListWidget list new QListWidget this list gt insertItem 0 tr Window1 list gt insertItem 1 tr Window2 QLab
  • C++ 多线程学习(二) 互斥锁std::mutex

    在多线程中经常会遇到多个线程同时修改同一个变量的情况 这个时候如果不对线程进行一定约束 很可能会导致意想不到的结果 例如有两个线程1和线程2 线程2的输入是线程1的结果 很显然如果在主线程中同时开启了线程1和线程2 它们是同时运行的 会直接
  • 华为机考108题(c++)(52-61)

    HJ52 计算字符串的编辑距离 描述 Levenshtein 距离 又称编辑距离 指的是两个字符串之间 由一个转换成另一个所需的最少编辑操作次数 许可的编辑操作包括将一个字符替换成另一个字符 插入一个字符 删除一个字符 编辑距离的算法是首先
  • 顺序表详解 —— 初始化、销毁、打印、增加、删除、查找、修改

    文章目录 顺序表介绍 初始化顺序表 销毁顺序表 打印顺序表 增加数据 头插 尾插 指定下标位置插入 删除数据 头删 尾删 指定下标位置删除 查找数据 修改数据 顺序表介绍 顺序表是在计算机内存中以数组的形式保存的线性表 线性表的顺序存储是指