数据结构---顺序表

news2024/11/25 4:39:47

专栏:数据结构
个人主页:HaiFan.
专栏简介:从零开始,数据结构!!

顺序表

  • 前言
  • 接口实现
  • SListInit初始化和SListDestory销毁
  • SListPrint打印表中的元素
  • SListCheckCapacity检查表中空间
  • SListPushBack尾插和SListPopBack尾删
  • SListPushFront头插和SListPopFront头删
  • SListFind查找元素
  • SListInset插入元素
  • SListErase删除元素
  • 完整代码

前言

在这里插入图片描述

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

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

接口实现

静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表。

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* val;
	int cnt;
	int capacity;
}SL;

void SListInit(SL* ps);//对顺序表进行初始化
void SListDestory(SL* ps);//使用动态分配函数开辟的空间需要free掉
void SListPrint(SL* ps);//打印出顺序表中的内容

void SListCheckCapacity(SL* ps);//检查顺序表中的空间是否够用

void SListPushBack(SL* ps,SLDataType x);//顺序表尾部插入
void SListPopBack(SL* ps);//尾部删除

void SListPushFront(SL* ps, SLDataType x);//头部插入
void SListPopFront(SL* ps);//头部删除

int SListFind(SL* ps,SLDataType x);//查找元素

void SListInsert(SL* ps, int pos, SLDataType x);//在任意位置插入元素

void SListErase(SL* ps, int pos);//删除任意位置的元素

要说明的是,这里为什么要把int重命名成SLDataType,因为元素的类型是可以变化的,想改变元素的类型,只需要在typedef这里改一下即可,就不需要在更改其他的数据了。

cnt是用来记录顺序表中的元素有多少个

capacity是用来检查顺序表中的空间是否够用

SListInit初始化和SListDestory销毁

顺序表初始化要把结构体中的val开辟一点空间。

void SListInit(SL* ps)
{
	ps->val = (SLDataType*)malloc(sizeof(SLDataType) * 4);
	if (ps->val == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	ps->capacity = 4;
	ps->cnt = 0;
}

在程序结束的时候,要把动态开辟的空间给销毁,用了多少空间,还给系统多少空间。

void SListDestory(SL* ps)
{
	free(ps->val);
	ps->val = NULL;
	ps->capacity = ps->cnt = 0;
}

SListPrint打印表中的元素

打印表中的元素,要实现这个只需要一个for循环就能解决。

void SListPrint(SL* ps)
{
	for (int i = 0; i < ps->cnt; i++)
	{
		cout << ps->val[i] << ' ';
	}
	puts("");
}

cnt是用来记录表中的元素个数的,

SListCheckCapacity检查表中空间

在进行增加元素的时候,要先对表中的空间进行一个检查,判断空间的大小是否足够在容纳一个元素。

void SListCheckCapacity(SL* ps)
{

	if (ps->capacity == ps->cnt)
	{

		SLDataType* tmp = (SLDataType*)realloc(ps->val, sizeof(SLDataType) * ps->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->val = tmp;
		ps->capacity *= 2;
	}
}

如果val是NULL,先通过malloc开辟一段空间,如果val不是NULL,就让cnt和capacity进行是否相等判断,如果相等,就使用realloc函数对val进行扩容,扩容的时候,用一个临时的指针接收,然后在把临时的指针赋值给val。

当然,空间扩容了,capacity也别忘记扩大了。

SListPushBack尾插和SListPopBack尾删

尾插很简单,cnt不但可以用来记录元素的个数的,也可以当作要插入的元素的下标。

元素值:1 2 3

下标: 0 1 2

cnt的值:3

此时在下标为cnt(3)的地方插入一个值即可。

void SListPushBack(SL* ps, SLDataType x)
{
	SListCheckCapacity(ps);

	ps->val[ps->cnt] = x;
	ps->cnt++;
}

当然,在插入元素之前,要先检查表的空间。


删除元素也很简单,只需要cnt–即可。

void SListPopBack(SL* ps)
{
	assert(ps->cnt);

	ps->cnt--;
}

这里要添加一个断言,避免没有元素了还执行删除操作。


SListPushFront头插和SListPopFront头删

头插的话,需要先把每个元素都往后移动一位,把第一个元素的位置给腾出来,才能把x给插入。

void SListPushFront(SL* ps, SLDataType x)
{
	SListCheckCapacity(ps);

	for (int i = ps->cnt; i > 0; i--)
	{
		ps->val[i] = ps->val[i - 1];
	}
	ps->val[0] = x;
	ps->cnt++;
}

当然,要先检查表中空间是否够用


头删的话,只需要把第一个元素等于第二个元素就行,即:下一个元素把上一个元素给覆盖了。

void SListPopFront(SL* ps)
{
	assert(ps->cnt);

	for (int i = 0; i < ps->cnt - 1; i++)
	{
		ps->val[i] = ps->val[i + 1];
	}
	ps->cnt--;
}

SListFind查找元素

查找元素的话,只需要遍历一遍表中元素即可,找到相同的值,返回下标

int SListFind(SL* ps, SLDataType x)
{
	assert(ps->cnt);

	for (int i = 0; i < ps->cnt; i++)
	{
		if (ps->val[i] == x)
		{
			return i;
			break;
		}
	}

	return -1;
}

SListInset插入元素

插入元素分为两种情况,当要插入的位置等于cnt时,就是尾插。

否则,就要让pos之后的元素依次往后移动一位,把pos位置空出来,在进行插入操作。

void SListInsert(SL* ps, int pos, SLDataType x)
{
	SListCheckCapacity(ps);

	if (pos > ps->cnt)
	{
		return;
	}
	else if (pos == ps->cnt)
	{
		SListPushBack(ps, x);
	}
	else
	{
		for (int i = ps->cnt; i > pos; i--)
		{
			ps->val[i] = ps->val[i - 1];
		}
		ps->val[pos] = x;
		ps->cnt++;
	}
	
}

SListErase删除元素

删除元素也分为两种情况,当pos等于cnt-1的时候,就是尾删。

否则,就要让pos后的元素,依次往前移动一位,把pos给覆盖即可。

void SListErase(SL* ps, int pos)
{
assert(ps);

if (pos == ps->cnt - 1)
{
	SListPopBack(ps);
}
else if (pos > ps->cnt)
{
	exit(-1);
}
else
{
	for (int i = pos; i < ps->cnt - 1; i++)
	{
		ps->val[i] = ps->val[i + 1];
	}
	ps->cnt--;
}

完整代码

.h文件

#pragma once

#include <iostream>
#include <stdlib.h>
#include <assert.h>

using namespace std;

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* val;
	int cnt;
	int capacity;
}SL;

void SListInit(SL* ps);//对顺序表进行初始化
void SListDestory(SL* ps);//使用动态分配函数开辟的空间需要free掉
void SListPrint(SL* ps);//打印出顺序表中的内容

void SListCheckCapacity(SL* ps);//检查顺序表中的空间是否够用

void SListPushBack(SL* ps,SLDataType x);//顺序表尾部插入
void SListPopBack(SL* ps);//尾部删除

void SListPushFront(SL* ps, SLDataType x);//头部插入
void SListPopFront(SL* ps);//头部删除

int SListFind(SL* ps,SLDataType x);//查找元素

void SListInsert(SL* ps, int pos, SLDataType x);//在任意位置插入元素

void SListErase(SL* ps, int pos);//删除任意位置的元素

.cpp文件

#define _CRT_SECURE_NO_WARNINGS 1


#include "SeqList.h"

void SListPrint(SL* ps)
{
	for (int i = 0; i < ps->cnt; i++)
	{
		cout << ps->val[i] << ' ';
	}
	puts("");
}


void SListInit(SL* ps)
{
	ps->val = (SLDataType*)malloc(sizeof(SLDataType) * 4);
	if (ps->val == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	ps->capacity = 4;
	ps->cnt = 0;
}

void SListDestory(SL* ps)
{
	free(ps->val);
	ps->val = NULL;
	ps->capacity = ps->cnt = 0;
}

void SListCheckCapacity(SL* ps)
{

	if (ps->capacity == ps->cnt)
	{

		SLDataType* tmp = (SLDataType*)realloc(ps->val, sizeof(SLDataType) * ps->capacity * 2);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		ps->val = tmp;
		ps->capacity *= 2;
	}
}

void SListPushBack(SL* ps, SLDataType x)
{
	SListCheckCapacity(ps);

	ps->val[ps->cnt] = x;
	ps->cnt++;
}

void SListPopBack(SL* ps)
{
	assert(ps->cnt);

	ps->cnt--;
}

void SListPushFront(SL* ps, SLDataType x)
{
	SListCheckCapacity(ps);

	for (int i = ps->cnt; i > 0; i--)
	{
		ps->val[i] = ps->val[i - 1];
	}
	ps->val[0] = x;
	ps->cnt++;
}

void SListPopFront(SL* ps)
{
	assert(ps->cnt);

	for (int i = 0; i < ps->cnt - 1; i++)
	{
		ps->val[i] = ps->val[i + 1];
	}
	ps->cnt--;
}

int SListFind(SL* ps, SLDataType x)
{
	assert(ps->cnt);

	for (int i = 0; i < ps->cnt; i++)
	{
		if (ps->val[i] == x)
		{
			return i;
			break;
		}
	}

	return -1;
}

void SListInsert(SL* ps, int pos, SLDataType x)
{
	SListCheckCapacity(ps);

	if (pos > ps->cnt)
	{
		return;
	}
	else if (pos == ps->cnt)
	{
		SListPushBack(ps, x);
	}
	else
	{
		for (int i = ps->cnt; i > pos; i--)
		{
			ps->val[i] = ps->val[i - 1];
		}
		ps->val[pos] = x;
		ps->cnt++;
	}
	
}

void SListErase(SL* ps, int pos)
{
	assert(ps);

	if (pos == ps->cnt - 1)
	{
		SListPopBack(ps);
	}
	else if (pos > ps->cnt)
	{
		exit(-1);
	}
	else
	{
		for (int i = pos; i < ps->cnt - 1; i++)
		{
			ps->val[i] = ps->val[i + 1];
		}
		ps->cnt--;
	}

}

test.cpp文件

#define _CRT_SECURE_NO_WARNINGS 1


#include "SeqList.h"

void TestSeqList()
{
	SL s;
	SListInit(&s);
	SListPushBack(&s, 1);
	SListPushBack(&s, 2);
	SListPushBack(&s, 3);
	SListPushBack(&s, 4);
	SListPushBack(&s, 5);
	SListPrint(&s);
	SListPopBack(&s);
	SListPrint(&s);
	SListPushFront(&s, -1);
	SListPushFront(&s, -2);
	SListPushFront(&s, -3);
	SListPushFront(&s, -4);
	SListPushFront(&s, -5);
	SListPrint(&s);
	SListPopFront(&s);
	SListPrint(&s);
	int ret  = SListFind(&s, 4);
	cout << ret << endl;
	SListInsert(&s, 3, 100000);
	SListPrint(&s);
	SListErase(&s, 3);
	SListPrint(&s);
	SListDestory(&s);
}

int main()
{
	TestSeqList();

	return 0;
}

在这里插入图片描述

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

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

相关文章

【项目设计】高并发内存池(一)[项目介绍|内存池介绍|定长内存池的实现]

&#x1f387;C学习历程&#xff1a;入门 博客主页&#xff1a;一起去看日落吗持续分享博主的C学习历程博主的能力有限&#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话&#xff1a; 也许你现在做的事情&#xff0c;暂时看不到成果&#xff0c;但不要忘记&…

IPVlan 详解

文章目录简介Ipvlan2同节点 Ns 互通Ns 内与宿主机 通信第三种方法Ns 到节点外部结论Ipvlan31. 同节点 Ns 互通Ns 内与宿主机 通信Ns 内到外部网络总结源码分析ipvlan 收包流程收包流程主要探讨使用 ipvlan 为 cni 通过虚拟网卡的实现。简介 ipvlan 和 macvlan 类似&#xff0c…

深度学习入门(六十七)循环神经网络——注意力机制

深度学习入门&#xff08;六十七&#xff09;循环神经网络——注意力机制前言循环神经网络——注意力机制课件心理学注意力机制注意力机制是显式地考虑随意线索非参注意力池化层Nadaraya-Watson 核回归&#xff1a;总结教材&#xff08;注意力提示&#xff09;1 生物学中的注意…

数据库系统:2. 关系数据库

更好的阅读体验\huge{\color{red}{更好的阅读体验}}更好的阅读体验 文章目录2.1 关系数据结构及形式化定义2.1.1 关系域笛卡尔积关系码三类关系基本关系的性质2.1.2 关系模式2.1.3 关系数据库2.1.4 关系模型的存储结构2.2 关系操作2.2.1 基本的关系操作2.2.2 关系数据语言的分类…

[visual studio]中,关于如何 【调试】 的问题 及 技巧

我们都知道&#xff0c;不会调试的程序员不是一个合格的程序员。 在初学阶段&#xff0c;由于对于语法的不熟悉&#xff0c;我们可能会写出很多语法错误&#xff0c;无法通过编译&#xff0c;编译器会报错&#xff0c;这种错误很好修改。 但是&#xff0c;随着我们不断敲代码…

当面试官问“你的SQL能力怎么样”时,怎么回答才不会掉进应聘陷阱?

在某平台看到一个比较实际的问题&#xff0c;在这里分享给职场新人。 SQL已经是职场最常用的一种编程语言&#xff0c;所以应聘技术或非技术岗位&#xff0c;都可能会被问道一个问题&#xff1a;你的SQL能力怎么样&#xff1f; 对于职场新人来说&#xff08;SQL高手可以无视下…

JavaScript事件循环

大厂面试题分享 面试题库后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★地址&#xff1a;前端面试题库一、异步执行原理1. 单线程的JavaScript我们知道&#xff0c;JavaScript是一种单线程语言&#xff0c;它主要用来与用户互动&#xff0c;以及操…

50-Jenkins-Lockable Resources插件实现资源锁定

Lockable Resources插件实现资源锁定前言安装插件使用插件资源配置Pipeline中使用前言 用来阻止多个构建在同一时间试图使用同一个资源。这里的资源可能是一个节点、一个代理节点、一组节点或代理节点的集合&#xff0c;或者仅仅是一个用于上锁的名字。如果指定的资源没有在全…

ASP.NET MVC | 创建应用程序

目录 首先 NO.1 No.2 App_Data 文件夹 Content 文件夹 Controllers 文件夹 Models 文件夹 Views 文件夹 Scripts 文件夹 最后 首先 一步一步的来&#xff0c;电脑上需要安装vs2019软件&#xff0c;版本高低无所谓&#xff0c;就是功能多少而已。 长这样的&#xff0…

无公网IP如何外网异地登录访问电商进销存系统?

电商进销存系统软件是电商企业必备的重要软件之一。 集订单管理、货品管理、采购管理等功能于一体&#xff0c;主要帮助广大电商用户实现准确、高效的订单处理及精细化的仓储管理。 电商进销存系统软件一般采用B/S结构&#xff0c;用户可在异地访问系统、查看货品库存及管理订…

第五期(2022-2023)传统行业云原生技术落地调研——金融篇 现已开启

随着数字化浪潮的来临&#xff0c;云原生技术正在改变着各行各业&#xff0c;通过IT变革驱动业务创新发展&#xff0c;促进企业自身以及产业生态的转型升级。 因此&#xff0c;灵雀云联合云原生技术实践联盟&#xff08;CNBPA&#xff09;和行业内头部厂商F5&#xff0c;共同发…

小黑子的线性代数:第一章

线代从入门到入土&#xff1a;一小黑子的线代系列&#xff1a;第一章1. 行列式1.1 二阶行列式1.2 三阶行列式1.3 小结2. 全排列与逆序数2.1 全排列2.2 逆序数3. 对换4. n阶行列式的定义5. 余子式和代数余子式6. 行列式的性质6.1 转置行列式6.2 对换变号6.3 提取公因子6.4 行列式…

华为OD机试C++实现 - 最小步骤数

最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…

GEE:样本点选择教程

本文记录了在GEE平台上标记样本的技巧和代码脚本&#xff0c;样本点可以用来做土地利用分类、植被提取、水藻提取、冰川提取、农作物提取等应用中。可以应用到的方法包括随机森林&#xff08;RF&#xff09;分类&#xff0c;支持矢量机&#xff08;SVM&#xff09;分类&#xf…

JavaSE之常用关键字学习

文章目录Java常用关键字学习1、static关键字学习1.1 用法一&#xff1a;修饰成员变量1.2 用法二&#xff1a;修饰成员方法1.3 用法三&#xff1a;修饰代码块1.4 用法四&#xff1a;修饰内部类类1.5 单例设计模式2、extends关键字学习2.1 继承的特点2.2 方法重写3、this、super关…

nvm基础命令

nvm基础命令 有了nvm之后就可以进行node下载了。下面举一个简单的例子&#xff1a; nvm version&#xff1a; 查看nvm版本 nvm list&#xff1a;查看本地拥有的node版本 nvm install xxx&#xff1a;安装版本号为xxx的node nvm use xxx&#xff1a;将node版本切换为xxx 以…

微信接口wx.login()、wx.request()中获取的内容不能赋值给全局变量(已解决)

小程序问题总结01 微信接口wx.login()、wx.request()中获取的内容不能赋值给全局变量&#xff08;已解决&#xff09; 在写登录模块的时候&#xff0c;需要使用微信的wx.login()接口获取临时code&#xff0c;并利用临时code向开发者服务器端发送请求&#xff0c;然后获取open…

自动化测试优势和劣势

一、自动化测试概述 软件自动化测试是相对手工测试而存在的&#xff0c;由测试人员根据测试用例中描述的规程一步步执行测试&#xff0c;得到实际结果与期望结果的比较。在此过程中&#xff0c;节省人力、时间或硬件资源&#xff0c;提高测试效率。 二、自动化测试优势&劣…

和日期相关的代码和bug——一道力扣题中的小发现

目录 Day of the Week 题目大意 常规方法 Python代码 Golang代码 C代码 基姆拉尔森公式 Python代码 Golang代码 C代码 使用库函数 Python代码 Golang代码 C代码 Day of the Week Given a date, return the corresponding day of the week for that date. The inp…

Photon Vectorized Engine 学习记录

Photon Hash Aggregation Vectorization Photon Hash Join 的向量化的要点是&#xff1a;使用开放地址法。步骤&#xff1a; 向量化计算 hash 值基于 hash 向量化计算 bucket 下标&#xff0c;得到 bucket index 向量基于 bucket index 向量中记录的下标找到 bucket&#xff…