[数据结构]顺序表

news2024/11/24 6:30:40

1、顺序表的概念及结构

1.1 线性表

线性表( linear list )是n个具有相同特性的数据元素的有限序列。 线性表是⼀种在实际中广泛使用的数据结构,常见的线性表:顺序表、链表、栈、队列、字符串...
线性表在逻辑上是线性结构,也就说是连续的⼀条直线。但是在物理结构上并不⼀定是连续的, 线性表在物理上存储时,通常以数组和链式结构的形式存储。
案例:蔬菜分为绿叶类、⽠类、菌菇类。线性表指的是具有部分相同特性的⼀类数据结构的集合

2、顺序表分类

2.1顺序表和数组的区别

顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接⼝

2.2顺序表分类

1.静态顺序表:

概念:使用定长数组存储元素

代码示例:

typrdef int SLDataType;
#define N 8
typedef struct SeqList
{
    SLDataType a[N];//定长数组
    int size;       //有效数据个数
}SL;

这就是一个静态顺序表,它又一定的缺陷。

容易出现:空间给少了不够用,给多了造成空间浪费

2.动态顺序表

它的特点是:按需申请

3.动态顺序表的实现

我们首先创建相应的头文件和程序文件

我们现在头文件中,引用头文件,定义所需要的结构体和函数

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* arr; //存储数据的底层结构
	int capacity;    //记录顺序表的空间大小
	int size;        //记录顺序表当前有效的数据个数
}SL;
//初始化:
void SLInit(SL* ps);
//销毁
void SLDestroy(SL* ps);
//顺序表的头部 / 尾部插入
void SLPushFront(SL* ps, SLDataType x);
void SLPushBack(SL* ps, SLDataType x);
//顺序表的头部 / 尾部删除 
void SLPopBack(SL* ps);
void SLPopFront(SL* ps);

//打印
void SLPrint(SL* ps);
//删除指定位置的值
void SLInsert(SL* ps, int pos, SLDataType x);
void SLErase(SL* ps, int pos);

我们先定义一个动态顺序表

注意:这行代码是为了设定我们的数据类型

1.初始化

接下来我们要初始化我们的顺序表。所以我们定义了这个函数

接着我们去源文件写完这个函数,让指针指向NULL大小设定为0完成初始化

void SLInit(SL* ps) 
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

写完了初始化我们可以开始写功能

首先就是头插和尾插

我们接着完善

2.头插

我们先来写头插函数

void SLPushFront(SL* ps, SLDataType x)

首先我们来思考以下问题,一个数组如何头插,以及目前的内存大小能否插入新的数据

假设足够:

数组头插,我们一般将数组的各个元素后移一位然后将数组arr[0]赋值成我们要插入的数据

void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
for (int i = ps->size; i > 0; i--) //i = 1
	{
		ps->arr[i] = ps->arr[i - 1]; //ps->arr[1] = ps->arr[0]
	}
	ps->arr[0] = x;
	ps->size++;
}

我们不难写出这个函数但是它对吗?

显然存在一定的问题,我们前面的条件是设置在空间充足的情况下,如果空间不足的话,我们该怎么办呢?

当然是扩容啦!!!

所以我们再写一个检查空间是否充足的函数,如果不足顺便扩容。

那么,既然说到扩容,我们应该怎样扩容呢?

我这里有三种扩容方式:

1.一次扩容一个空间

2.一次扩容多个大小的空间

3.成倍的增加空间(1.5倍,2倍)

这里我推荐第三种方法。

理由:

        第一种一次扩容一个空间,好处是不会造成空间的浪费,缺点是如果我们输入大量数据时,它需要多次开辟,导致程序效率低下。

        第二种一次开辟多个空间,有效解决了第一种导致程序小路低下的问题,但是,它也有相应的问题,我们不能确定一次开辟多大的空间合适,如果开辟小了,一样也会和第一种一样多次扩容,影响程序效率,但如果一下周四开辟空间过大,也会导致空间被浪费。

我们先定义函数:

void SLCheckCapacity(SL* ps)

接着判断是否需要扩容,然后扩容空间,但是由于我们初始化直接是NULL所以这里我再加上一个三目操作符,总体代码如下:

void SLCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL) {
			perror("realloc fail!");
			exit(1);
		}
		//扩容成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}

这里我设置了tmp变量是为了防止扩容失败。这里我选择的就是扩容原来的两倍。

接下来我们按照上面的思路把头插完善

void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > 0; i--) //i = 1
	{
		ps->arr[i] = ps->arr[i - 1]; //ps->arr[1] = ps->arr[0]
	}
	ps->arr[0] = x;
	ps->size++;
}

3.尾插

做完了头插,我们可以来试试尾插,数组中尾插是神简单的,如图:

如果空间充足,我们可以直接再尾部插入我们的数据然后吧size++,不够的话先扩容然后再执行

void SLPushBack(SL * ps, SLDataType x)
{
		assert(ps);
		SLCheckCapacity(ps);
		ps->arr[ps->size++] = x;
}

这样头插和尾插就完成了

4.头删

完成了插入那么我们还需要完成删除,删除相比较插入它有什么不同?删除不需要太在意空间。

现在我们先来完成头删。

在数组中我们怎么完成头删的呢?如图

我们一般是把每个数向前移动一位,数组有效长度-1,及size--;

代码示例:

void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}

注意:我们要确保ps和ps->size不为NULL

5.尾删

这个操作实现起来其实非常简单,我们可以直接size--;

代码示例:

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

完成这些,那么我要上难度了,删除指定位置的值/插入指定位置的值

6.删除指定位置的值

具体思路,就是遍历去寻找所需数值,然后并将该数值之后的数据的下标前移,siza--如图:

代码示例:

void SLErase(SL* ps, int pos) {
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	//pos以后的数据往前挪动一位
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];//ps->arr[i-2] = ps->arr[i-1];
	}
	ps->size--;
}

7.在指定位置插入值

思路,找到数值将该数值及其后的向后移动一位。size++

如图:

代码示例:

void SLInsert(SL* ps, int pos, SLDataType x) {
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);

	SLCheckCapacity(ps);

	//pos及之后的数据往后挪动一位,pos空出来
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1]; //ps->arr[pos+1] = ps->arr[pos]
	}
	ps->arr[pos] = x;
	ps->size++;
}

注:这是插入,要检查空间是否足够

8.打印

完成这些我们可以来尝试打印我们的顺序表,类似打印数组。

代码示例:

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

9.销毁顺序表

在我们之前讲过动态内存开辟,最后要再释放。

代码示例:

void SLDestroy(SL* ps) 
{
	assert(ps);

	if (ps->arr) {
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}

最后来展示程序代码:

#include"SeqList.h"
void SLInit(SL* ps) 
{
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}
void SLDestroy(SL* ps)
{
	assert(ps);

	if (ps->arr) {
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}
void SLCheckCapacity(SL* ps)
{
	if (ps->size == ps->capacity)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, newCapacity * sizeof(SLDataType));
		if (tmp == NULL) {
			perror("realloc fail!");
			exit(1);
		}
		//扩容成功
		ps->arr = tmp;
		ps->capacity = newCapacity;
	}
}
void SLPushBack(SL * ps, SLDataType x)
{
		assert(ps);
		SLCheckCapacity(ps);
		ps->arr[ps->size++] = x;
}
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > 0; i--) //i = 1
	{
		ps->arr[i] = ps->arr[i - 1]; //ps->arr[1] = ps->arr[0]
	}
	ps->arr[0] = x;
	ps->size++;
}
void SLPopBack(SL* ps)
{
	
	assert(ps);
	assert(ps->size);   
	ps->size--;
	
}
void SLPopFront(SL* ps)
{
	assert(ps);
	assert(ps->size);
	for (int i = 0; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}
void SLInsert(SL* ps, int pos, SLDataType x) {
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	SLCheckCapacity(ps);
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1]; //ps->arr[pos+1] = ps->arr[pos]
	}
	ps->arr[pos] = x;
	ps->size++;
}
void SLErase(SL* ps, int pos) 
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];
	}
	ps->size--;
}
void SLPrint(SL* ps) 
{
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");
} 
void SLDestroy(SL* ps) 
{
	assert(ps);

	if (ps->arr) {
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->size = ps->capacity = 0;
}
//指定位置之前插入数据
void SLInsert(SL* ps, int pos, SLDataType x) {
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);

	SLCheckCapacity(ps);

	//pos及之后的数据往后挪动一位,pos空出来
	for (int i = ps->size; i > pos; i--)
	{
		ps->arr[i] = ps->arr[i - 1]; //ps->arr[pos+1] = ps->arr[pos]
	}
	ps->arr[pos] = x;
	ps->size++;
}
//删除指定位置数据
void SLErase(SL* ps, int pos) {
	assert(ps);
	assert(pos >= 0 && pos < ps->size);

	//pos以后的数据往前挪动一位
	for (int i = pos; i < ps->size - 1; i++)
	{
		ps->arr[i] = ps->arr[i + 1];//ps->arr[i-2] = ps->arr[i-1];
	}
	ps->size--;
}

这样一个循序表完成了,你可以用设计的函数来进行操作。

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

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

相关文章

47. 全排列 II - 力扣(LeetCode)

题目描述 给定一个可包含重复数字的序列 nums &#xff0c;按任意顺序 返回所有不重复的全排列。 输入示例 nums [1,1,2]输出示例 [[1,1,2], [1,2,1], [2,1,1]]解题思路 解题代码 class Solution {List<List<Integer>> result new ArrayList<>();Deq…

探索元宇宙:游戏的全新境界

你是否曾经想过&#xff0c;在一个完全由你自己掌控的虚拟世界里&#xff0c;体验前所未有的冒险和刺激&#xff1f; UTONMOS元宇宙游戏将带你进入这个全新的领域&#xff0c;让你的想象力和创造力自由驰骋。 UTONMOS&#xff0c;基于上海和数集团自主研发的和数链&#xff0c…

MoEs学习

和多任务学习的mmoe很像哦&#xff08;有空再学习一下&#xff09;moe layer的起源&#xff1a;Switch Transformers paper MoE moe由两个结构组成&#xff1a; Moe Layer &#xff1a;这些层代替了传统 Transformer 模型中的前馈网络 (FFN) 层。MoE 层包含若干“专家”(例如…

【教程】混淆Dart 代码

什么是代码混淆&#xff1f; 代码混淆是一种将应用程序二进制文件转换为功能上等价&#xff0c;但人类难于阅读和理解的行为。在编译 Dart 代码时&#xff0c;混淆会隐藏函数和类的名称&#xff0c;并用其他符号替代每个符号&#xff0c;从而使攻击者难以进行逆向工程。 Flut…

dubbo和eureka的区别

dubbo可以作为客户端&#xff0c;也可以作为服务端&#xff0c;因此他内置了很多序列化框架可供选择&#xff0c;通过配置可以进行选择。默认是hession&#xff0c;还有gson&#xff0c;fastJson&#xff0c;jdk自带的序列化。 eureka只能作为服务端&#xff0c;他序列要与客户…

LeetCode 670 最大交换数

周一&#xff0c;非常冷&#xff0c;大风呼呼的&#xff0c;上班路都走不动。 好消息&#xff0c;马上要过年了。大风吹&#xff0c;天气好。 过年过年&#xff0c;回家过年~ 学生时代的迷茫是不应该存在的&#xff0c;最好的时光应该尽情享受&#xff0c;而不应该自己给加层…

【zlm】针对单个设备的码率的设置

目录 代码修改 实验数据一 实验数据二 同时拉一路视频后 修改记录 使用方法 代码修改 要被子类引用 &#xff0c;所以放在protected 不能放private 下面的结论&#xff0c;可以在下面的实验数据里引用。“同时拉一路视频后” 实验数据一 https://10.60.3.45:10443/index…

深度学习如何弄懂那些难懂的数学公式?是否需要学习数学?

经过1~2年的学习&#xff0c;我觉得还是需要数学有一定认识&#xff0c;重新捡起高等数学、概率与数理、线代等这几本&#xff0c;起码基本微分方程、求导、对数、最小损失等等还是会用到。 下面给出几个链接&#xff0c;可以用于平时充电学习。 知乎上的&#xff1a; 机器学…

目标检测 - RCNN系列模型

文章目录 1. RCNN2. Fast-RCNN3. Faster-RCNN 1. RCNN 论文&#xff1a;Rich feature hierarchies for accurate object detection and semantic segmentation 地址&#xff1a;https://arxiv.org/abs/1311.2524 分为两个阶段&#xff1a; 目标候选框Object ProposalsProposal…

C语言float 类型数如何与0值⽐较?

一、问题 写出 float a 与“0值”⽐较的if语句。 二、解答 1、问题分析与解答 ⼀般地&#xff0c;如果⽤证判断⼀个数值型变量(short、int、long 等)&#xff0c;应该⽤ if(a0)&#xff0c;表示的含义是a与0进⾏“数值”上的⽐较; 但 float 型变量并不精确&#xff0c;不能直…

docker里安装conda,并source本地已有的虚拟环境包

有的环境比较难配&#xff0c;在镜像里配置的版本总是与本地不同&#xff0c;导致程序起不来&#xff0c;今天就用个最基础的镜像&#xff0c;去配置anaconda&#xff0c;然后直接导入虚拟环境。 本次使用镜像&#xff1a;nvcr.io/nvidia/cuda:12.2.0-runtime-ubuntu20.04&…

2024阿里云优惠活动隐藏页面,必看!

阿里云优惠活动隐藏页面之前在官网是可以看到的&#xff0c;2024阿里云官网升级后这个页面隐藏了&#xff0c;阿里云百科分享给大家阿里云优惠活动隐藏页面 aliyunbaike.com/go/activity 这是阿里云最新优惠活动集合页面&#xff0c;当前所有的活动都在这个页面&#xff0c;还有…

Ubuntu及CentOS 离线下载安装文件方法说明

一、离线安装包说明 Centos 包后缀名: rpm 安装方法&#xff1a;sudo rpm -ivh package.rpm Ubuntu 包后缀名字&#xff1a; deb 安装方法&#xff1a; sudo dpkg -i <package_file.deb> 二、手动下载 https://pkgs.org/ 通过网站搜索需要的离线包&#xff0c;选择…

数据库防水坝是什么?有什么作用?有哪些优势?

数据库是公司重要IT资产&#xff0c;是公司数据存储、数据整合、数据备份等重要载体。所以保障数据库安全至关重要。目前保障数据库安全产品较多&#xff0c;例如堡垒机、防火墙、数据库防水坝等等。今天我们就先来简单了解一下数据库防水坝是什么&#xff1f;有什么作用&#…

【位运算专题】介绍+详解5道题

本文讲解位运算的基础介绍和详解6道题&#xff0c;在讲解题目的同时提供AC代码【注&#xff1a;点击题目可打开对应链接】 1、位运算的基础介绍【重点】 如果上面位图不了解的&#xff0c;可以看我之前写过的文章&#xff1a; 【C和数据结构】位图和布隆过滤器-CSDN博客 2、…

LeetCode.670. 最大交换

题目 题目链接 分析 这道题的意思是我们只能交换一次&#xff0c;需要得到最大的数字。 我们的第一个想法就是要这个数字先变成一个数组&#xff0c;便于我们操作。 然后把数组最大的数放到第一个位置&#xff0c;如果最大的数字已经在第一个位置&#xff0c;那么就把次大的…

司铭宇老师:二手房电话营销培训:二手房电话销售技巧和话术

二手房电话营销培训&#xff1a;二手房电话销售技巧和话术 一、二手房电话销售的重要性 1.高效传播&#xff1a;通过电话&#xff0c;我们可以迅速将房源信息传播给潜在客户&#xff0c;提高房源的曝光率。 2.精准定位&#xff1a;通过电话沟通&#xff0c;我们可以初步了解客户…

掌握Vim:提升编程效率的实用指南

掌握Vim&#xff1a;提升编程效率的实用指南 1. 引言常用命令解析基础命令编辑命令搜索和替换移动和跳转窗口和标签页 Vim配置优化vimrc文件的基本设置常用配置项高级配置技巧 推荐插件及使用NERDTree&#xff1a;项目文件浏览YouCompleteMe&#xff1a;代码自动补全vim-gitgut…

[Unity] Tilemap瓦片左右翻转(上下翻转)

Tile&#xff08;瓦片&#xff09;左右翻转感觉是很常用的一个功能啊&#xff01;看了一些教程都没有提及&#xff0c;心想难道要把每张Sprite再做一张对称的、再做成瓦片吗&#xff1f; 图片量x2 、瓦片量x2、不现实&#xff01;一定有方法&#xff01; 搜索了了半天没找到方…

基于flask徐州市天气信息可视化分析系统04600-计算机毕业设计项目选题推荐(附源码)

摘 要 信息化社会内需要与之针对性的信息获取途径&#xff0c;但是途径的扩展基本上为人们所努力的方向&#xff0c;由于站在的角度存在偏差&#xff0c;人们经常能够获得不同类型信息&#xff0c;这也是技术最为难以攻克的课题。针对天气信息等问题&#xff0c;对天气信息进行…