【1】C语言实现顺序表

news2024/11/16 21:34:16

文章目录

  • Ⅰ 概念及结构
    • 1. 静态顺序表
    • 2. 动态顺序表
  • Ⅱ 基本操作实现
    • 1. 定义顺序表
    • 2. 初始化顺序表
    • 3. 销毁顺序表
    • 4. 输出顺序表
    • 5. 扩容顺序表
    • 6. 尾插法插入数据
    • 7. 头插法插入数据
    • 8. 尾删法删除数据
    • 9. 头删法删除数据
    • 10. 顺序表查找
    • 11. 在指定位置 pos 插入数据
    • 12. 删除指定位置 pos 的元素

Ⅰ 概念及结构

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

顺序表的分类

  1. 静态顺序表:使用固定长度的数组来存储元素。
  2. 动态顺序表:使用动态开辟的数组来存储元素。

1. 静态顺序表

  • 顺序表的长度固定,一次性开辟一块连续的数组空间。
  • 开辟的空间多了就浪费空间,开辟的空间少了这块空间就没用了。

定义静态顺序表

#define MAX 10
typedef int SLDataType;		//顺序表的每个数据类型

typedef struct SeqList
{
	SLDateType data[MAX];	//定长数组(顺序表)
	int size;				//当前顺序表内有效数据的个数
}SeqList;

在这里插入图片描述

定长顺序表的缺点

  • 顺序表在实际使用过程中没办法确定数组大小,MAX 给小了不够用,给大了浪费。
  • 静态的顺序表在实际使用中实用性低,因此本文后面对于顺序表的操作都是基于动态顺序表来实现的。

静态顺序表的定义

2. 动态顺序表

  • 动态顺序表可以根据需求申请数组空间,动态顺序表的空间没有不够这种说法。因此在实际使用中使用的更多的还是动态顺序表。

定义动态顺序表

typedef int SLDataType;		//顺序表的每个数据类型

typedef struct SeqList		//sequence list
{
	SLDataType* data;		//指向动态开辟的数组空间
	int size;				//有效数据的个数
	int capacity;			//数组所能容纳的数据个数
}SeqList;

Ⅱ 基本操作实现

  • 在定义各个操作顺序表的函数时,使用的是址传递,否则形参无法改变实参。

1. 定义顺序表

  • 本文使用的都是动态顺序表
typedef int SLDataType;		//顺序表的每个数据类型

typedef struct SeqList		//sequence list
{
	SLDataType* data;		//指向动态开辟的数组空间
	int size;				//有效数据的个数
	int capacity;			//数组所能容纳的数据个数
}SeqList;

2. 初始化顺序表

void SeqListInit(SeqList* ps)		
{
	assert(ps);

	ps->data = NULL;	
	ps->size = 0;		//初始化有效数据个数为 0
	ps->capacity = 0;	//初始化最大容纳数量为 0
}

3. 销毁顺序表

  • 释放开辟好的连续的空间,将有效数据个数和空间容量都置为 0.
void SeqListDestroy(SeqList* ps)
{
	assert(ps);

	if (ps->data != NULL)	//顺序表不为空
	{
		free(ps->data);		
		ps->data = NULL;
		ps->capacity = 0;
		ps->size = 0;
	}
}

4. 输出顺序表

//打印顺序表
void SeqListPrint(SeqList* ps)		
{
	assert(ps);

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

5. 扩容顺序表

对顺序表进行扩容时有两种情况

  1. 顺序表不为空:直接将顺序表的容量使用 realloc 扩容两倍即可。
  2. 顺序表为空:此时 capacity 为 0 不能按两倍来扩容,直接给一个固定值即可。
//检查顺序表是否需要扩容
void SLCheckCapacity(SeqList* ps)	
{
	assert(ps);

	//有效数据 = 容纳数量 时就要扩容了
	if (ps->size == ps->capacity)	
	{
		//顺序表容量为 0 时直接开辟 4 个元素的空间,反之按照 2 倍扩容
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* tmp = 
		(SLDataType*)realloc(ps->data, sizeof(SLDataType) * newcapacity);

		if (NULL == tmp)//用 tmp 而不是用 ps->data 是防止开辟空间失败时将原地址覆盖
		{
			perror("realloc");
			return;
		}

		ps->data = tmp;				//让 data 指向扩容后的空间
		ps->capacity = newcapacity;	//顺序表容量扩大成新的容量
	}
}

6. 尾插法插入数据

  • 将元素插入到当前顺序表的末尾。

在这里插入图片描述

//尾插法插入数据
void SeqListPushBack(SeqList* ps, SLDataType x)
{
	assert(ps);

	SLCheckCapacity(ps);	//插入元素前看看是否要先扩容

	ps->data[ps->size] = x;	//将 x 插入到顺序表当前的末尾
	ps->size++;				//继续指向下一个末尾
}

7. 头插法插入数据

头插概念

将每个要插入的数据都插入在 下标为 0 的位置上。头插时有两种情况

  1. 顺序表内无数据:直接将要插入的数据放在下标为 0 的位置。

在这里插入图片描述

  1. 顺序表内有数据:将顺序表内原来的所有元素都后移一位,然后将新元素插入到下标 0 的位置。

在这里插入图片描述

实现思路

  • 使用一个变量 end 指向顺序表的最后一个元素,当 end 不小于 0 的时候将 end 指向的数据依次往后挪。
  • 因为 end 是下标,顺序表最后一个元素的下标应该为顺序标的有效个数 - 1。

在这里插入图片描述

实现代码

//头插法插入数据
void SeqListPushFront(SeqList* ps, SLDataType x)
{
	assert(ps);

	SLCheckCapacity(ps);					//插入前看看是否需要扩容

	int end = ps->size - 1;					//顺序表最后一个元素的下标
	while (end >= 0)						//end 不越界就一直将元素往后挪
	{
		ps->data[end + 1] = ps->data[end];	//将元素后挪一位
		end--;								//让 end 指向更前一个元素
	}

	ps->data[0] = x;						//将要插入的元素插入到下标 0 的位置
	ps->size++;								//顺序表有效个数 + 1
}

8. 尾删法删除数据

  • 删掉顺序表的最后一个元素。
  • 直接将顺序表的有效个数 - 1即可,在删除之前还应该先判断顺序表内是否有有效元素。如果有效个数 size 为 0 还继续 - 1 的话直接就越界了。

在这里插入图片描述

//尾删法删除数据
void SeqListPopBack(SeqList* ps)
{
	assert(ps && ps->size > 0);

	ps->size--;	//这样原来的第 size 个数据就不再是有效数据了
}

9. 头删法删除数据

  • 每次删除数据都是将下标为 0 的数据给删除掉。
  • 只需要将下标 0 后面的数据依次往前覆盖上来,就可以直接将头元素删除掉了。

实现思路

  1. 定义一个 begin 变量初始值为 1,将 begin 指向的值往前挪到 begin - 1 的位置。
  2. 然后讲 begin++ 指向下一个元素,再继续重复第一步。

在这里插入图片描述

实现代码

//头删法删除数据
void SeqListPopFront(SeqList* ps)
{
	assert(ps && ps->size > 0);

	int begin = 1;

	while (begin < ps->size)
	{
		ps->data[begin - 1] = ps->data[begin];//让后一个元素往前覆盖
		begin++;
	}

	ps->size--;
}

10. 顺序表查找

  • 遍历顺序表内所有的有效数据,如果等于要查找的值,则返回下标值,反之返回 -1。
// 顺序表查找
int SeqListFind(SeqList* ps, SLDataType x)
{
	assert(ps && ps->size > 0);

	for (int i = 0; i < ps->size; i++)
	{
		if (ps->data[i] == x)
		{
			return i;	//找到了则返回该元素在顺序表内的下标
		}
	}

	return -1;			//找不到则返回 -1
}

11. 在指定位置 pos 插入数据

pos 的下标在合法时有两种情况

  1. 0 <= pos < size

    • 定义一个 end 变量指向顺序表内的最后一个有效数据 (size - 1 的位置),从 end 开始依次将数据往后挪,直到 end 移动到小于 pos 的位置时说明已经全部挪动完毕,此时直接将新数据插入到下标为 pos 的位置即可。

在这里插入图片描述

  1. pos == size:此时要插入的位置在最后一个元素之后,直接将元素插入即可。

在这里插入图片描述

// 顺序表在 pos 位置插入 x
void SeqListInsert(SeqList* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);	//指定的位置在合法范围内

	int end = ps->size - 1;					//指向顺序表的最后一个有效数据

	while (end >= pos)						//如果 pos > end 则直接执行尾插法
	{
		ps->data[end + 1] = ps->data[end];	//将 pos 后的元素依次往后挪
		end--;								//指向前一个元素
	}

	ps->data[pos] = x;						//在 pos 下标处插入新元素
 	ps->size++;								//顺序表有效数据个数 + 1
}

12. 删除指定位置 pos 的元素

  • 将 pos 位置后的元素依次往前覆盖,和头删法一样
  • pos 的位置此时就不能等于 size 了,最后一个元素下标是 size - 1,不能删除下标为 size 的元素。

pos 的下标在合法时有两种情况

  1. 0 <= pos < size - 1:直接将 pos 后的元素依次往前覆盖。
  2. pos == size - 1:要删除的是最后一个元素,直接将顺序表有效数据个数 - 1 即可。
// 顺序表删除pos位置的值
void SeqListErase(SeqList* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	int begin = pos + 1;		//指向 pos 后的一个数据
								//pos 如果等于 size - 1 则 begin = size

	while (begin < ps->size)	//依次往前覆盖元素,如果要删除最后一个则不进入循环.
	{
		ps->data[begin - 1] = ps->data[begin];
		begin++;		
	}

	ps->size--;					//顺序表有效数据个数 - 1
}

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

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

相关文章

【算法】动态规划之LeetCode 53.最大子数组和

目录 文章目录 **目录**&#x1f4d1;前言1.题目描述2. 动态规划法 &#x1f4d1;文章末尾 &#x1f4d1;前言 本文主要是leetcode题解析&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁…

联想方案服务斩获CCF技术发明奖,助力云原生技术发展

10月27日&#xff0c;中国计算机学会&#xff08;CCF&#xff09;公布了我国计算机科技领域最具权威性的科技奖项——2023年度“CCF科技成果奖”评选结果&#xff0c;共有41个项目荣获2023年度CCF科技成果奖。由联想集团与上海交通大学等共同研究开发的《面向互联网服务的云原生…

【机器学习合集】模型设计之网络宽度和深度设计 ->(个人学习记录笔记)

文章目录 网络宽度和深度设计1. 什么是网络深度1.1 为什么需要更深的模型浅层学习的缺陷深度网络更好拟合特征学习更加简单 2. 基于深度的模型设计2.1 AlexNet2.2 AlexNet工程技巧2.3 VGGNet 3. 什么是网络宽度3.1 为什么需要足够的宽度 4. 基于宽度模型的设计4.1 经典模型的宽…

错误 LNK1112 模块计算机类型“x64”与目标计算机类型“X86”冲突

这个错误表明你在进行链接时&#xff0c;模块的计算机类型与目标计算机类型冲突。 在这里&#xff0c;“x64”代表64位系统&#xff0c;“X86”代表32位系统。 要解决这个问题&#xff0c;你需要确保你的所有模块&#xff08;包括库文件和依赖项&#xff09;都是与你的目标计…

《算法通关村—队列基本特征和实现问题解析》

《算法通关村—队列基本特征和实现问题解析》 队列的基本特征 队列&#xff08;Queue&#xff09;是一种常见的数据结构&#xff0c;具有以下基本特征&#xff1a; 先进先出&#xff08;FIFO&#xff09;&#xff1a;队列中的元素按照它们被添加到队列的顺序排列&#xff0c;…

Matlab论文插图绘制模板第123期—水平正负柱状图

在之前的文章中&#xff0c;分享了很多Matlab柱状图的绘制模板&#xff1a; 进一步&#xff0c;再来看一种特殊的柱状图&#xff1a;水平正负柱状图。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;本期内容『数据代码』已上传资源群中&#xff0c;加群的朋友请自行下…

人到中年应该怎么交朋友

听人劝、吃饱饭,奉劝各位小伙伴,不要订阅该文所属专栏。 作者:不渴望力量的哈士奇(哈哥),十余年工作经验, 跨域学习者,从事过全栈研发、产品经理等工作,现任研发部门 CTO 。荣誉:2022年度博客之星Top4、博客专家认证、全栈领域优质创作者、新星计划导师,“星荐官共赢计…

Doris数据库FE——FeServer

FeServer feServer new FeServer(Config.rpc_port);feServer.start();FeServer&#xff08;Doris frontend thrift server&#xff09;职责是负责FE和BE之间通信。如下即为初始化中关于FeServer类的构造函数和start函数的具体代码。其start函数流程和构建thrift server行为一致…

springboot网上商城购物系统

第1章 绪论 1.1背景及意义 随着社会的快速发展&#xff0c;计算机的影响是全面且深入的。人们生活水平的不断提高&#xff0c;日常生活中人们对网上商城购物系统方面的要求也在不断提高&#xff0c;购物的人数更是不断增加&#xff0c;使得网上商城购物系统的开发成为必需而且…

synchronized 同步锁的思考

经过前面的分析&#xff0c;我们大概对同步锁有了一些基本的认识&#xff0c;同步锁的本质就是实现多线程的互斥&#xff0c;保证同一时刻只有一个线程能够访问加了同步锁的代码&#xff0c;使得线程安全性得到保证。下面我们思考一下&#xff0c;为了达到这个目的&#xff0c;…

毕业工作之后,没有在学校中考试排名这种方式,那如何确定自己是不是一直在退步还是在进步

在职场中衡量自己是否在进步或者退步&#xff0c;相较于学校里通过考试排名来判断要复杂得多。因为职场的评价标准更为多样&#xff0c;同时还涉及到个人职业发展、工作满意度等方面。下面是一些你可以用来判断自己是否在进步的方法&#xff1a; 1. 目标设定与达成 给自己设定…

【数据结构与算法】二叉树基础OJ--下(巩固提高)

前言&#xff1a; 上一篇文章我们讲到二叉树基础oj题目的练习&#xff0c;此篇文章是完成基础oj练习的完结篇。 传送-->【数据结构与算法】二叉树基础OJ -- 上 (巩固提高)-CSDN博客 &#x1f4a5;&#x1f388;个人主页:​​​​​​Dream_Chaser&#xff5e; &#x1f388…

分类预测 | Matlab实现SSA-ELM麻雀优化算法优化极限学习机分类预测

分类预测 | Matlab实现SSA-ELM麻雀优化算法优化极限学习机分类预测 目录 分类预测 | Matlab实现SSA-ELM麻雀优化算法优化极限学习机分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.MATLAB实现SSA-ELM麻雀优化算法优化极限学习机分类预测&#xff08;Matlab完整…

微信小程序云开发如何实现多条件多字段模糊查询

之前的博文中&#xff0c;已经跟大家介绍过&#xff0c;微信小程序云开发如何实现单条件单字段的模糊查询&#xff0c;这个是很常见的业务需求。在一些更复杂的场景下&#xff0c;我们需要实现多条件多字段的模糊查询&#xff0c;比如同时兼容对商品名称、类别、产地等多条件的…

Canvas录制视频

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

AI:41-基于基于深度学习的YOLO模型的玉米病害检测

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

idea使用MyBatisX插件

1.MyBatisX功能 (1).实现mapper和xml的跳转 (2).自动生成java文件&#xff0c;比如mapper、service、dao、pojo 2.安装MyBatisX插件 install后然后重启idea即可 3.使用MyBatieX实现mapper和xml跳转 &#xff08;1&#xff09;.点击mapper中的红色图标即可跳转到对应的xml方…

算法通过村第十八关-回溯|青铜笔记|什么叫回溯(初篇)

文章目录 前言从N叉树说起为什么有的问题暴力搜索也不行总结 前言 提示&#xff1a;我对你透露一个大密码&#xff0c;这是人类最古老的玩笑。往哪走&#xff0c;都是往前走。 --米兰昆德拉 回溯是非常重要的算法思想之一&#xff0c;主要解决一些暴力枚举也搞不定的问题&#…

第五章 I/O管理 五、输入/输出应用程序接口设备驱动程序接口

目录 一、应用程序接口 二、阻塞和非阻塞I/O 阻塞I/O: 非阻塞I/O: 三、设备驱动程序 一、应用程序接口 以前的统一接口不适用了&#xff0c;现在改为了几种不同的接口 二、阻塞和非阻塞I/O 阻塞I/O: 应用程序发出I/O系统调用&#xff0c;进程需转为阻塞态等待。 eg:字符…

40 深度学习(四):卷积神经网络|深度可分离卷积|colab和kaggle的基础使用

文章目录 卷积神经网络为什么要卷积卷积的具体流程池化tensorflow代码 深度可分离卷积原理介绍计算量对比代码参数计算例子 colab 和 kagglecolabkaggle如何在colab上使用kaggle的数据 卷积神经网络 卷积神经网络的基本结构 1&#xff1a; (卷积层(可选)池化层) * N全连接层 *…