顺序表详解(如何实现顺序表)

news2024/11/13 9:29:49

文章目录


前言

在进入顺序表前,我们先要明白,数据结构的基本概念。


一、数据结构的基本概念

1.1什么是数据结构

数据结构是由“数据”和“结构”两词组合而来。所谓数据就是?常见的数值1、2、3、4.....、姓名、性别、年龄,等。这些都是数据。所谓结构就是当我们想要使用大量同⼀类型的数据时,我们可以借助数组这样的数据结构将大量的数据组织在⼀起,结构也可以理解为组织数据的方式。

1.2数据结构的两个层次

数据结构的两个层次分为逻辑结构和存储结构,逻辑结构与数据的存储无关独立于计算机从具体问题抽象出来的数学模型模。逻辑结构分为线性结构和非线性结构,这里不再强调。存储结构分为顺式存储结构和链式存储结构,今天我们所说的顺序表就是顺数存储结构,链式存储结构的代表就是链表。

1.3最基础的数据结构:数组

二.顺序表的概念及结构

概念:之前说了最基础的数据结构就是数组,它的概念:顺序表其实就是数组,但是在宿主的基础上,他还要求数据必须从头开始连续存放,并且中间不能跳跃间隔

2.1结构

 顺序表它分为静态顺序表和动态顺序表

静态顺序表

静态顺序表需要用#define来开辟,静态的特点就是N给小了不够用,给大了又浪费,所以我们所说的顺序表一般都是指的动态顺序表。

动态顺序表

2.2接口函数

接口函数就是某个模块写了(主要)给其它模块用的函数。简单的说接口函数就是类中的公有数。顺序表的实现主要是以接口函数来实现的

三.动态顺序表的实现

顺序表(seplist),我们重命名为SL,完成这个它我们使用3个文件,SL.h来放函数的声明,SL.cpp来放函数的定义,test.c来放可执行程序。

3.1一个经典的错误(初始化)

void SLInit(SL ps)
{
	ps.a = NULL;

	ps.size = ps.capacity = 0;

}

void testSL1()
{
    SL S1;
    SLInit(SL);
}

为什么这个代码无法运行???

因为在函数中的形参跟实参是有区别的形参的改变,不会影响到实参的,形参只是实参的一份临时拷贝,所以要用指针来找地址。

所以正确的初始化应该要这样

void SLInit(SL* ps)
{
	ps->a = NULL;

	ps->size = ps->capacity = 0;

}


void testSL1()
{
    SL S1;

    SLInit(&SL);
}

3.2接口函数之尾插

在一个数组中,如果我们想在末尾插入一个数,我们该怎么插入呢?这就是我们要想如何完成这个接口函数。

往末尾插东西,我们就要做到3点考虑,一.没有空间,刚刚好,二.空间不够的时候要进行扩容,三.空间足够的时候我们就直接插入。

先来看最容易的情况就是直接尾删

void SLpushBack(SL* ps, SLDataType x)
{
	ps->a[ps->size] = x;
	ps->size++;
}

然后我们在想我们前三点要注意的事情,如果没有空间或者空间不足了的话,我就要扩容,我们可以先将有效个数和空间容量相等来形成一个新的有效空间,这里我用了一个三目操作符,如果他们都等于零,我就给他付个值不等于零,我就翻倍在这个地方的扩容,我们就能想到realloc函数的扩容。过完之后我们还要判断一下,如果为空指针的话我们就要报警告,最后把我开辟的新空间重新付给a就可以了。

void SLPushBack(SL* ps, SLDataType x)
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));

		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}

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

	ps->a[ps->size] = x;
    ps->size++;

}

其实扩容这一步,我们完成了另外一种接口函数的使用,那就是检查扩容,我们可以用一个步骤来开辟一个新的结构函数就是检查扩容void SLCheckCapacity(SL* ps);这样对于后面的来使用就会更加方便。

3.3接口函数之尾删

尾删就非常简单了,我们只要防止数组越界就可以了,我们这里利用断言来警告他不能越界。

void SLPopBack(SL* ps)
{
	assert(ps->size > 0);
	{
		ps->size--;
	}
}

3.4接口函数之头插

头插的话想在第一个数前放一个位置,我们就把已经存放的数每个都向后移一个,注意:如果容量空间已到最大则需开辟空间,所以这就用到了我们之前所讲的检查扩容这个接口函数,所以在头差之前我们先要来检查一下扩容,如果容量够就可以进行头差,如果不够就扩容。

void SLPushFront(SL* ps, SLDataType x)
{
	SLCheckCapacity(ps);
	//挪动数据
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}

3.5接口函数之头删

先思考为什么头删不可以size--???

因为根据顺序表的概念必须从头开始连续存放,并且中间不能跳跃间隔。

所以这个地方我们采取先挪动在尾删的方式。

void SLPopFront(SL* ps)
{
	assert(ps->size > 0);
		//挪动数据
	int begin = 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

3.6还原空间

因为我们之前动态开辟了内存,所以说我们肯定要把这个内存进行释放。

void SLDestory(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}

3.7接口函数之查找

查找的意思就是说找到对应元素所在的下标,即便他有多个也没关系,顺序表是从头到尾开始存放的,但是存放的内容不一定需要从头到尾他还可以存放字符等各种变量。

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

3.8接口函数之在指定的pos下标位置插入

pos下标也是有要求,他不可以违背顺序表的概念

其实挪动方法都是一样的,不管是尾插还是头插它的移动方法其实是一样的

void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	int end = ps->size - 1;
	while(end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}

3.9接口函数之删除pos下标位置的数据

其实挪动方法都是一样的,不管是尾插还是头插它的移动方法其实是一样的,挪动的方式是一样的,只是可能方向不一样,做法是一样的,然后我们还是要判断下标的合法性

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

4.0复用

这个时候有没有突然间恍然大悟大!!!

之前写的头删尾删头差尾插好像都可以用pos去代替去完善

头删
void PushBack(SL* ps)
{
	SLErase(ps, ps->0);
}
尾删
void SLPopBack(SL* ps)
{
	SLErase(ps, ps->size-1);
}
头插
void SLPushFront(SL* ps, SLDataType x)
{
	SLInsert(ps, ps->0,X);
}
尾插
void SLpushBack(SL* ps, SLDataType x)
{
	SLInsert(ps, ps->size, X);
}

这就是复用。

四.整体的实现

SL.h
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//#define N 1000
typedef int SLDataType;
#pragma once
typedef struct SeqList
{
	SLDataType * a;//动态开辟的数组大小
	int size; // 有效数据个数
	int capacity; // 空间容量

}SL;
void SLInit (SL* ps);//初始化
void SLPrint(SL* ps);//打印
void SLCheckCapacity(SL* ps);//检查扩容
void SLDestory(SL* ps);//销毁,还原空间
void SLpushBack(SL* ps, SLDataType x);//尾插
void SLPopBack(SL* ps);//尾删
void SLPushFront(SL* ps, SLDataType x);//头插
void SLPopFront(SL* ps);//头删
int SLFind(SL* ps, SLDataType x);//查找
void SLInsert(SL* ps, int pos, SLDataType x);//在指定的pos下标位置插入
void SLErase(SL* ps, int pos);//删除pos位置的数据
SL.cpp
#include"SL.h"
//初始化
void SLInit(SL* ps)
{
	ps->a = NULL;
	ps->size = ps->capacity = 0;

}

//打印
void SLPrint(SL* ps)
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d", ps->a[i]);
	}
	printf("\n");
}

//检查扩容
void SLCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newcapacity * sizeof(SLDataType));

		if (tmp == NULL)
		{
			printf("realloc fail\n");
			exit(-1);
		}

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

//销毁,还原空间
void SLDestory(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->capacity = ps->size = 0;
}

//尾插
void SLpushBack(SL* ps, SLDataType x)
{
	ps->a[ps->size] = x;
	ps->size++;
}

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

//头插
void SLPushFront(SL* ps, SLDataType x)
{
	SLCheckCapacity(ps);
	//挪动数据
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}

//头删
void SLPopFront(SL* ps)
{
	assert(ps->size > 0);
		//挪动数据
	int begin = 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
	ps->size--;
}

//查找
int SLFind(SL* ps, SLDataType x)
{
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->a[ps->size] == x)
		{
			return i;
		}
	}
	return -1;
}

//在指定的pos下标位置插入
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	int end = ps->size - 1;
	while(end >= pos)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[pos] = x;
	ps->size++;
}

//删除pos位置的数据
void SLErase(SL* ps, int pos)
{
	assert(pos >= 0 && pos < ps->size);
	int begin = pos + 1;
	while (begin < ps->size)
	{
		ps->a[begin - 1] = ps->a[begin];
		begin++;
	}
}

//头删
//void PushBack(SL* ps)
//{
//	SLErase(ps, ps->0);
//}
//尾删
//void SLPopBack(SL* ps)
//{
//	SLErase(ps, ps->size-1);
//}
//头插
//void SLPushFront(SL* ps, SLDataType x)
//{
//	SLInsert(ps, ps->0,X);
//}
//尾插
//void SLpushBack(SL* ps, SLDataType x)
//{
//	SLInsert(ps, ps->size, X);
//}

总结

有了顺序表,为什么还要学习其他的数据结构?顺序表作为数据结构的最基本,假设数据量非常庞大,频繁的获取数字,有效数据个数会影响程序的执行程序所以说最基础的数据结构提供的操作已经不能完全满足复杂的算法实现只有不断地提升自己才能变得强大。

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

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

相关文章

高维数据的中介效应【中介分析】《R包:HIMA》

允许基于高级中介筛选和惩罚回归技术来估计和测试高维中介效应 Hima包浏览 高维中介示意图 图1. 在暴露和结果之间有高维中介的情况 本包的作用 在确定独立筛选和极小极大凹惩罚技术的基础上&#xff0c;采用联合显著性检验方法对调解效果进行检验。使用蒙特卡罗模拟研究来展…

C#知识点-15(匿名函数、使用委托进行窗体传值、反射)

匿名函数 概念&#xff1a;没有名字的函数&#xff0c;一般情况下只调用一次。它的本质就是一个方法&#xff0c;虽然我们没有定义这个方法&#xff0c;但是编译器会把匿名函数编译成一个方法 public delegate void Del1();//无参数无返回值的委托public delegate void Del2(s…

Java SE 入门到精通—基础语法【Java】

敲重点&#xff01; 本篇讲述了比较重要的基础&#xff0c;是必须要掌握的 1.程序入口 在Java中&#xff0c;main方法是程序的入口点&#xff0c;是JVM&#xff08;Java虚拟机&#xff09;执行Java应用程序的起始点。 main方法的方法签名必须遵循下面规范&#xff1a; publ…

TestNG与ExtentReport单元测试导出报告文档

TestNG与ExtentReport集成 目录 1 通过实现ITestListener的方法添加Reporter log 1.1 MyTestListener设置 1.2 输出结果 2 TestNG与ExtentReporter集成 2.1 项目结构 2.2 MyExtentReportListener设置 2.3 单多Suite、Test组合测试 2.3.1 单Suite单Test 2.3…

Java实现实验室耗材管理系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 耗材档案模块2.2 耗材入库模块2.3 耗材出库模块2.4 耗材申请模块2.5 耗材审核模块 三、系统展示四、核心代码4.1 查询耗材品类4.2 查询资产出库清单4.3 资产出库4.4 查询入库单4.5 资产入库 五、免责说明 一、摘要 1.1…

WebSocket实现聊天

基于webSocket通信的库主要有 socket.io&#xff0c;SockJS&#xff0c;这次用的是 SockJS。 这里我们使用sockjs-client、stomjs这两个模块&#xff0c;要实现webSocket通信&#xff0c;需要后台配合&#xff0c;也使用相应的模块。 WebSocket 1、http&#xff1a;http超文…

War Robots可以使用5347的卡支付

很多小伙伴想使用War Robots&#xff0c;但是不知道怎么弄&#xff0c;方法比较可靠&#xff0c;亲测有效~~~ 可以使用Fomepay的5347的卡支付 卡片cvc就是卡密&#xff0c;在首页点击更多时可以查看

【ubuntu2004安装N卡驱动】

软硬件环境 硬件&#xff1a;联想notebook16&#xff0c;显卡4060laptop 软件&#xff1a; ubuntu20.04 驱动安装成功的版本&#xff1a;NVIDIA-Linux-x86_64-535.146.02.run 使用默认的驱动安装&#xff0c;没用原因如下 让手动安装。 手动安装 环境准备&#xff1a; sudo …

【shap】使用shap画图时colorbar颜色条不能正常显示

下面&#xff0c;我的shap值全是蓝色的&#xff0c;没有红色 &#xff08;注&#xff1a;蓝色是负贡献&#xff0c;红色是正贡献&#xff09; 参考上面的帖子&#xff0c;是matplotlib版本问题&#xff0c;我原来的版本是3.5.0&#xff0c;降级回3.4.3就正常了。

心律守护 基于机器学习的心脏病预测

心律守护 基于机器学习的心脏病预测 心律守护 基于机器学习的心脏病预测项目背景与意义项目数据与特征数据分析与预处理机器学习模型建立与评估结语 心律守护 基于机器学习的心脏病预测 在当今数字化时代&#xff0c;机器学习的应用已经渗透到了医疗保健领域的各个层面。其中&…

阿里云/腾讯云幻兽帕鲁服务器为什么更新/重启之后,服务器存档没了?

有的朋友说&#xff0c;他的阿里云幻兽帕鲁服务器重启了一下后&#xff0c;服务器存档就没了&#xff1f;这是怎么回事呢&#xff0c;其实可能的原因&#xff0c;一是服务器还有重启完成&#xff0c;也就是游戏服务端还没有启动&#xff0c;就登进去&#xff0c;可能会显示网络…

Eclipse项目间的引用

我们在开发的时候&#xff0c;有时候需要把一个大的项目打散&#xff0c;尤其是现在微服务的架构很流行&#xff0c;一个大的项目往往被拆成很多小的项目&#xff0c;而有的项目作为公共工程被独立出来&#xff0c;比如有个工程专门提供各种Util工具类&#xff0c;有的工程专门…

使用 Docker 安装 Elasticsearch 8.4.3

使用 Docker 安装 Elasticsearch 8.4.3 一. 拉取 Elasticsearch Docker 镜像二. 使用Docker启动单节点集群三. 修改密码 前言 这是我在这个网站整理的笔记,有错误的地方请指出&#xff0c;关注我&#xff0c;接下来还会持续更新。 作者&#xff1a;神的孩子都在歌唱 从 Elastic…

基于Python的热点分析预警系统

项目&#xff1a;基于Python的热点分析预警系统 摘 要 基于网络爬虫的数据可视化服务系统是一种能自动从网络上收集信息的工具&#xff0c;可根据用户的需求定向采集特定数据信息的工具&#xff0c;本项目通过研究爬取微博网来实现微博热点分析数据信息可视化系统功能。对于采…

美国纽约时代广场纳斯达克大屏投放-大舍传媒

美国纽约时代广场纳斯达克大屏投放-大舍传媒 引言 对于大舍传媒来说&#xff0c;能够在美国纽约时代广场纳斯达克大屏投放广告是一个里程碑式的时刻。这不仅仅代表着大舍传媒在全球范围内的知名度与实力&#xff0c;也标志着该公司在国际市场上取得了巨大的进展。纽约时代广场…

sqllabs第46关 order by 注入

简介&#xff1a;&#xff08;order by注入-错误回显-POST注入&#xff09; 请求方法&#xff1a;POST 方法&#xff1a;order by注入错误回显数字型注入 先了解下 order by参数注入&#xff1a; order by 注入是指其后面的参数是可控的&#xff0c; order by 不同于我们在 whe…

威来国际教育:留学服务的全新标杆,打造无忧留学体验

在当今全球化日益加深的背景下&#xff0c;留学已成为众多年轻人拓宽视野、提升个人能力的重要手段。随着留学市场的不断扩大和留学目的地的多样化&#xff0c;家庭和学生在选择留学服务时更加注重专业性和全面性。 在这一领域&#xff0c;威来国际教育凭借其深厚的背景和专业的…

一、vue3+ts项目框架搭建——规范

新建项目及规范配置 1.1项目初始化 1.1.1环境准备1.1.2初始化项目 1.2项目配置 一、eslint配置 1.1vue3环境代码校验插件1.2.eslintrc.cjs配置文件 1.3运行脚本 二、配置prettier:格式化工具 2.1安装依赖包2.2.prettierrc.json添加规则2.3.prettierignore忽略文件 三、配置st…

Vue3-组合式Api(重点)

阅读文章你可以收获的知识 1.知道setup语法糖的使用和如何实现的 2.知道在vue3中如何定义响应式数据 3.知道在vue3中如何定义一个计算属性&#xff08;computed&#xff09; 4.知道如何在vue3中使用watch来监听数据 5.知道在vue3如何实现父子通信 6.知道vue3如何使用ref函…

苍穹外卖学习-----2024/02/21

1.新增员工 /*** 处理SQL异常* param sqlIntegrityConstraintViolationException* return*/ExceptionHandlerpublic Result exceptionHandler(SQLIntegrityConstraintViolationException sqlIntegrityConstraintViolationException){//String message sqlIntegrityConstraintV…