顺序表——“数据结构与算法”

news2025/7/19 7:05:29

各位CSDN的uu们你们好呀,今天小雅兰的内容是数据结构与算法里面的顺序表啦,在我看来,数据结构总体上是一个抽象的东西,关键还是要多写代码,下面,就让我们进入顺序表的世界吧


线性表

顺序表


线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...

线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。


 顺序表

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

顺序表就是数组,但是在数组的基础上,它还要求数据是从头开始连续存储的,不能跳跃间隔 

顺序表一般可以分为:

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

#define _CRT_SECURE_NO_WARNINGS 1
#define N 7
#include"SeqList.h"
typedef int SLDateType;
typedef struct SeqList
{
	SLDateType arr[N];//定长数组
	size_t size;//表示数组中存储了多少数据
}SL;

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

#define _CRT_SECURE_NO_WARNINGS 1
#define N 7
#include"SeqList.h"
typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* arr;//指向动态开辟的数组
	size_t size;//表示数组中存储了多少数据
	size_t capicity;//数组实际能存储数据的空间容量是多大
}SL;

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

在这里,所有函数命名风格都是跟着STL走的,方便小雅兰日后的学习!!! 


顺序表的初始化:

void SeqListInit(SL* ps)//顺序表的初始化
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

注意:在这里,不可以使用传值调用的方式,只能使用传址调用的方式

void SeqListInit(SL ps)//顺序表的初始化
{
	ps.arr = NULL;
	ps.size = ps.capacity = 0;
}

万万不能使用这样的方式初始化,因为:在函数传参的时候,形参是实参的一份临时拷贝,对形参的修改并不会影响实参

 顺序表的打印:

void SeqListPrint(SL* ps)//顺序表的打印
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}

扩容:

void SeqListCheckCapacity(SL* ps)//检查空间,如果满了,进行扩容
{
	//如果没有空间或者空间不足,那么我们就扩容
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDateType* tmp = (SLDateType*)realloc(ps->arr, newcapacity * sizeof(SLDateType));
		if (tmp == NULL)
		{
			printf("realloc fail!\n");
			exit(-1);
		}
		ps->arr = tmp;
		ps->capacity = newcapacity;
	}
}

顺序表销毁:

void SeqListDestroy(SL* ps)//顺序表销毁
{
	free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}

尾插:

void SeqListPushBack(SL* ps, SLDateType x)//尾插
{
	SeqListCheckCapacity(ps);
	ps->arr[ps->size] = x;
	ps->size++;
}

尾删:

void SeqListPopBack(SL* ps)//尾删
{
	assert(ps->size > 0);
	ps->size--;
}

 头插:

void SeqListPushFront(SL* ps, SLDateType x)//头插
{
	SeqListCheckCapacity(ps);
	//挪动数据
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[0] = x;
	ps->size++;
}

头删:

void SeqListPopFront(SL* ps)//头删
{
	assert(ps->size > 0);
	//挪动数据
	int begin = 0;
	while (begin < ps->size-1)
	{
		ps->arr[begin] = ps->arr[begin+1];
		++begin;
	}
	ps->size--;
}
另一种写法:
void SeqListPopFront(SL* ps)//头删
{
	assert(ps->size > 0);
	//挪动数据
	int begin = 1;
	while (begin < ps->size)
	{
		ps->arr[begin - 1] = ps->arr[begin];
		++begin;
	}
	ps->size--;
}

 顺序表查找:

//顺序表查找
//找到了返回x位置的下标,没有找到返回-1
int SeqListFind(SL* ps, SLDateType x)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1;
}

 指定pos下标位置插入:

// 顺序表指定pos下标位置插入x
void SeqListInsert(SL* ps, size_t pos, SLDateType x)
{
	温柔的写法
	//if (pos > ps->size || pos < 0)
	//{
	//	printf("pos invalid!\n");
	//}
	//粗暴的写法
	assert(pos <= ps->size || pos >= 0);
	SeqListCheckCapacity(ps);
	//挪动数据
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[pos] = x;
	ps->size++;
}

 然后,写出了这个函数的功能之后,我们发现:可以对之前写的头插和尾插搞一些事情,下面,我们开始搞事情!!!

头插和尾插:

void SeqListPushBack(SL* ps, SLDateType x)//尾插
{
	SeqListInsert(ps, ps->size, x);
}
void SeqListPushFront(SL* ps, SLDateType x)//头插
{
	SeqListInsert(ps, 0, x);
}

 删除pos位置的数据:

//顺序表删除pos位置的数据
void SeqListErase(SL* ps, size_t pos)
{
	assert(pos < ps->size || pos >= 0);
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->arr[begin - 1] = ps->arr[begin];
		++begin;
	}
	ps->size--;
}

写出这个函数的功能之后,我们又可以搞事情啦!!!

头删和尾删:

void SeqListPopBack(SL* ps)//尾删
{
	SeqListErase(ps, 0);
}
void SeqListPopFront(SL* ps)//头删
{
	SeqListErase(ps, ps->size - 1);
}

菜单:

void menu()
{
	printf("#############################################\n");
	printf("\n");
	printf("###################1.头插#####################\n");
	printf("\n");
	printf("###################2.头删#####################\n");
	printf("\n");
	printf("###################3.尾插######################\n");
	printf("\n");
	printf("###################4.尾删######################\n");
	printf("\n");
	printf("###################5.打印#####################\n");
	printf("\n");
	printf("###################0.exit#####################\n");
	printf("\n");
	printf("##############################################\n");
}

其实,最好不要一上来就写菜单,先写单元测试,菜单不方便调试

 测试菜单函数:

void MenuTest()
{
	SL s1;
	SeqListInit(&s1);
	int input = 0;
	int x;
	while (input != -1)
	{
		menu();
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入你要头插的数据,以-1结束:");
			while (x != -1)
			{
				SeqListPushFront(&s1, x);
				scanf("%d", &x);
			}
			break;
		case 2:
			SeqListPopFront(&s1);
			break;
		case 3:
			printf("请输入你要尾插的数据,以-1结束:");
			while (x != -1)
			{
				SeqListPushBack(&s1, x);
				scanf("%d", &x);
			}
			break;
		case 4:
			SeqListPopBack(&s1);
			break;
		case 5:
			SeqListPrint(&s1);
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("输入错误,请重新输入\n");
		}
	}
}

源代码如下:

SeqList.h的内容:

#pragma once
#include<stdio.h>
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdlib.h>
#include<assert.h>
#define N 7
typedef int SLDateType;
//顺序表的动态存储
typedef struct SeqList
{
	SLDateType* arr;//指向动态开辟的数组
	size_t size;//表示数组中存储了多少数据
	size_t capacity;//数组实际能存储数据的空间容量是多大
}SL;
//基本增删查改接口
void SeqListInit(SL* ps);//顺序表的初始化
void SeqListPrint(SL* ps);//顺序表的打印
void SeqListCheckCapacity(SL* ps);//检查空间,如果满了,进行扩容
void SeqListDestroy(SL* ps);//顺序表销毁
void SeqListPushBack(SL* ps, SLDateType x);//尾插
void SeqListPopBack(SL* ps);//尾删
void SeqListPushFront(SL* ps, SLDateType x);//头插
void SeqListPopFront(SL* ps);//头删
//顺序表查找
//找到了返回x位置的下标,没有找到返回-1
int SeqListFind(SL* ps, SLDateType x);
//顺序表指定pos下标位置插入x
void SeqListInsert(SL* ps, size_t pos, SLDateType x);
//顺序表删除pos位置的数据
void SeqListErase(SL* ps, size_t pos);

SeqList.c的内容:

#define _CRT_SECURE_NO_WARNINGS 1
#include"SeqList.h"
void SeqListInit(SL* ps)//顺序表的初始化
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}
void SeqListPrint(SL* ps)//顺序表的打印
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
}
void SeqListCheckCapacity(SL* ps)//检查空间,如果满了,进行扩容
{
	//如果没有空间或者空间不足,那么我们就扩容
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDateType* tmp = (SLDateType*)realloc(ps->arr, newcapacity * sizeof(SLDateType));
		if (tmp == NULL)
		{
			printf("realloc fail!\n");
			exit(-1);
		}
		ps->arr = tmp;
		ps->capacity = newcapacity;
	}
}
void SeqListDestroy(SL* ps)//顺序表销毁
{
	free(ps->arr);
	ps->arr = NULL;
	ps->capacity = ps->size = 0;
}
void SeqListPushBack(SL* ps, SLDateType x)//尾插
{
	SeqListCheckCapacity(ps);
	ps->arr[ps->size] = x;
	ps->size++;
}
void SeqListPopBack(SL* ps)//尾删
{
	assert(ps->size > 0);
	ps->size--;
}
void SeqListPushFront(SL* ps, SLDateType x)//头插
{
	SeqListCheckCapacity(ps);
	//挪动数据
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[0] = x;
	ps->size++;
}
void SeqListPopFront(SL* ps)//头删
{
	assert(ps->size > 0);
	//挪动数据
	int begin = 1;
	while (begin < ps->size)
	{
		ps->arr[begin - 1] = ps->arr[begin];
		++begin;
	}
	ps->size--;
}
//顺序表查找
//找到了返回x位置的下标,没有找到返回-1
int SeqListFind(SL* ps, SLDateType x)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == x)
		{
			return i;
		}
	}
	return -1;
}
// 顺序表指定pos下标位置插入x
void SeqListInsert(SL* ps, size_t pos, SLDateType x)
{
	温柔的写法
	//if (pos > ps->size || pos < 0)
	//{
	//	printf("pos invalid!\n");
	//}
	//粗暴的写法
	assert(pos <= ps->size || pos >= 0);
	SeqListCheckCapacity(ps);
	//挪动数据
	int end = ps->size - 1;
	while (end >= pos)
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[pos] = x;
	ps->size++;
}
//顺序表删除pos位置的数据
void SeqListErase(SL* ps, size_t pos)
{
	assert(pos < ps->size || pos >= 0);
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->arr[begin - 1] = ps->arr[begin];
		++begin;
	}
	ps->size--;
}

好啦,小雅兰今天的内容就到这里啦,数据结构的的确确是一个麻烦的东西,还要加油呀!!!

 

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

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

相关文章

为什么要用VR全景?5个答案告诉你

看中了刚上市的一款新车&#xff0c;再也不用等车展、去4s店才能仔细观赏&#xff0c;点开手机就能“置身”车内近距离观看每一处细节&#xff0c;点击关灯开灯、关门关门&#xff0c;除了摸不到&#xff0c;和在现场几乎没有区别&#xff1b; 准备买房的时候&#xff0c;没人愿…

Git 基础(一)—— Git 的安装及其配置

目录 一、Git 的下载与安装 1、Linux 环境 2、Windows 环境 (1) 下载 Git 安装包 (2) 安装 Git 二、Git 配置 1、配置用户信息 2、查看配置信息 3、Windows 环境下配置文件的位置 一、Git 的下载与安装 1、Linux 环境 在保证网络环境畅通的情况下&#xff0c;直接输…

L298N 直流电机驱动模块与 Arduino

L298N 直流电机驱动模块与 Arduino 原文地址 L298N 电机驱动器可以控制两个直流电机的速度和旋转方向。 此外&#xff0c;它还可以控制双极步进电机&#xff0c;例如NEMA 17。如果您想了解更多信息&#xff0c;请查看本教程。 L298N电机驱动器和Arduino控制步进电机&#xff…

基于C/C++综合训练 ----- 贪吃蛇

文章目录一、定义结构体对象二、游戏初始化1. 蛇初始化2. 食物初始化3. 围墙初始化4. 界面初始化三、逻辑编程1. 启动游戏2. 打印成绩3. main函数四、细节处理五、程序源码该篇环境为Visual Studio2022 游戏简述 &#xff1a;在控制终端绘画出一个矩阵表示游戏界面(围墙)&…

android h5餐饮管理系统myeclipse开发mysql数据库编程服务端java计算机程序设计

一、源码特点 android h5餐饮管理系统是一套完善的WEBandroid设计系统&#xff0c;对理解JSP java&#xff0c;安卓app编程开发语言有帮助&#xff08;系统采用web服务端APP端 综合模式进行设计开发&#xff09;&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要…

javaEE初阶 — HTML 中的常见标签

文章目录注释标签标题标签&#xff1a;h1 h6段落标签&#xff1a;p换行标签&#xff1a;br格式化标签图片标签&#xff1a;img1. img 的 alt 属性2. img 的 title 属性3. width 与 heigth 属性用来描述图的尺寸超链接标签&#xff1a;a表格标签列表标签表单标签1. from 标签2. …

【C++的OpenCV】第十一课-OpenCV图像常用操作(八):直方图计算(cv.calc())

&#x1f389;&#x1f389;&#x1f389;欢迎各位来到小白piao的学习空间&#xff01;\color{red}{欢迎各位来到小白piao的学习空间&#xff01;}欢迎各位来到小白piao的学习空间&#xff01;&#x1f389;&#x1f389;&#x1f389; &#x1f496;&#x1f496;&#x1f496…

发布新闻稿的流程与步骤

发布新闻稿需要遵循一定的流程和步骤&#xff0c;以下是一般的新闻发布流程&#xff1a;1、编写新闻稿新闻稿的内容应当简洁、明确、准确&#xff0c;力求突出新闻价值和亮点。企业和组织可以根据新闻稿的主题和目的&#xff0c;选择不同的写作风格和语言表达方式&#xff0c;以…

春季训练营 | 前端+验证直通车-全实操项目实践,履历加成就业无忧

“芯动的offer”是2023年E课网联合企业全新推出集训培优班&#xff08;线下&#xff09;&#xff0c;针对有一定基础&#xff08;linux、verilog、uvm等&#xff09;在校学生以及想要通过短时间的学习进入到IC行业中的转行人士&#xff0c;由资深IC设计工程师带教&#xff0c;通…

openpnp - 贴片前, 放入一块新板子后, 对板子的坐标矫正

文章目录openpnp - 贴片前, 放入一块新板子后, 对板子的坐标矫正概述笔记实验前置条件实验开始建立自己板子上的Mark点封装, 用于自己人工圈定判断Mark点位置是否正确建立mark点封装根据多个mark点, 来精确定位板子左下角原点坐标ENDopenpnp - 贴片前, 放入一块新板子后, 对板子…

图像边缘检测

文章目录前言一、图像边缘检测二、边缘检测算子1. Roberts算子2. Prewitt算子3. Sobel算子三、代码实现总结前言 有了图像放大缩小&#xff0c;图像灰度化处理等相关基础知识过后&#xff0c;就可以进行图像边缘检测了。边缘检测最后也会在FPGA上面实现&#xff0c;此处小编已经…

神经网络分类任务(手写数字识别)

1.Mnist分类任务 网络基本构建与训练方法&#xff0c;常用函数解析 torch.nn.functional模块 nn.Module模块 学习方法&#xff1a;边用边查&#xff0c;多打印&#xff0c;duogua 使用jupyter的优点&#xff0c;可以打印出每一个步骤。 2.读取数据集 自动下载 %matplotl…

移动设备配置文件管理

什么是移动设备上的设备配置文件 随着移动设备在工作中使用量的迅速增加&#xff0c;有必要将这些设备置于企业管理之下&#xff0c;以确保企业数据安全且设备符合行业标准。移动设备上的配置文件允许 IT 管理员通过对员工使用的智能手机、平板电脑和笔记本电脑实施公司策略和…

三维人脸实践:基于Face3D的渲染、生成与重构 <一>

face3d: Python tools for processing 3D face git code: https://github.com/yfeng95/face3d paper list: PaperWithCode 该方法广泛用于基于三维人脸关键点的人脸生成、属性检测&#xff08;如位姿、深度、PNCC等&#xff09;&#xff0c;能够快速实现人脸建模与渲染。推荐…

学生使用的台灯该怎么选择?2023适合学生房间的灯推荐

随着社会的进步发展&#xff0c;我们的生活水平越来越高&#xff0c;很多家庭的孩子都开始使用台灯这种家居产品&#xff0c;对于学习任务繁重的他们来说&#xff0c;台灯确实可以起到保护眼睛、提高学习专注度的作用。那么不知道朋友们是否了解过&#xff0c;台灯该怎么选择呢…

本地开发vue项目联调遇到访问接口跨域问题

本地开发vue项目联调遇到访问接口跨域问题 修改本地的localhost 一&#xff1a;按winr打开运行窗口&#xff0c;输入drivers &#xff0c;然后回车 二&#xff1a;打开etc文件夹&#xff0c;然后用记事本的方式打开里面的hosts文件&#xff0c; 三&#xff1a;这时我们就可…

oneblog_justauth_三方登录配置【QQ】

文章目录oneblog添加第三方平台QQ互联平台创建三方应用完善信息登录oneblog添加第三方平台 1.oneblog管理端&#xff0c;点击左侧菜单 网站管理——>社会化登录配置管理 ,添加一个社会化登录 2.编辑信息如下&#xff0c;选择QQ平台后复制redirectUri,然后去QQ互联平台获取…

UART 串口通信

第18.1讲 UART串口通信原理讲解_哔哩哔哩_bilibili 并行通信 一个周期同时发送8bit的数据&#xff0c;占用引脚资源多 串行通信 串行通信的通信方式&#xff1a; 同步通信 同一时钟下进行数据传输 异步通信 发送设备和接收设备的时钟不同 但是需要约束波特率&#xff08;…

大数据|HDFS分布式文件系统

前文回顾&#xff1a;Hadoop系统 目录 &#x1f4da;HDFS概述 &#x1f4da;HDFS在设计时的假设和目标 &#x1f4da;HDFS的基本特征 &#x1f4da;HDFS的体系结构 &#x1f407;目录节点 &#x1f407;数据节点 &#x1f4da;HDFS的副本机制 &#x1f4da;HDFS的数据存…

KD500全自动电容电感测试仪

一、产品特点 1.本仪器采用了先进的测量原理与四端测量技术&#xff0c;可以精确测量、测试重复性能好&#xff1b; 2.能在不拆线的状态下&#xff0c;测量成组并联着的单个电容器的电容量和成组并联着电容器组的总电容量&#xff1b; 3.大屏幕液晶显示屏&#xff08;320X24…