顺序表的基本操作

news2024/11/13 9:36:44

目录

一.什么是顺序表

二.顺序表的基本操作

  1.初始化

2.增容

3.尾插

4.头插

5.尾删

6.头删

7.指定位置插入

8.指定位置删除

9.打印

10.查找

11.销毁


一.什么是顺序表

        顺序表是用一段物理地址连续 的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。
        顺序表一般分为静态顺序表和动态顺序表,静态顺序表一般是用定长数组存储,而动态顺序表则是用动态内存管理函数进行动态分配空间,当空间不够时可以进行增容
        静态顺序表:
#define MAX 100
typedef int SLDataType;//对类型重定义,方便适应不同的数据类型
struct SeqList
{
    SLDataType a[MAX];//定长数组
    int size;         //当前数据个数
};

动态顺序表:

typedef int SLDataType;//对类型重定义,方便适应不同的数据类型
typedef struct SeqList
{
	SLDataType *a;//定义指针指向动态开辟的空间
	int size;    //当前存储的数据个数
	int capacity; //数据最大个数
}SL;

        一般我们不太经常使用静态顺序表,因为实际需求往往空间都是不定的,因此我们只讨论动态顺序表

        顺序表的本质还是对数组进行操作,只是和数组有所不同的是,顺序表的数据是连续存放的

二.顺序表的基本操作

        一般地,我们都是用结构体定义顺序表,对顺序表的基本操作分为初始化,插入,删除,打印,查找,增容等操作,下面我们就来学习一下这些基本操作

  1.初始化

        顺序表的初始化我们只需要讲指针置为空指针,然后将当前数据元素个数和最大数据元素个数置为0,到插入时我们便会动态开辟空间给指针a

void SLInit(SL * ps)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	ps->a = NULL;//置为空指针
	ps->size = 0;//初始化为0
	ps->capacity = 0;
}

2.增容

        当当前数据元素个数等于最大数据元素个数时,说明空间已满,此时则需要我们进行扩容,而扩容需要我们利用的动态内存管理函数开辟空间,我们选择的是realloc函数,打开cpp网站查看该函数有关信息

          realloc函数的的两个参数分别为空间的地址和扩容后的空间大小,返回值是指向扩容后空间的地址,返回值void*,因此我们需要将其强制类型转换为我们需要的类型

        当realloc函数的第一个指针为空指针时,其作用相当于malloc,第一次增容,由于我们初始化时给了最大容量capacity为0,因此需要给capacity赋一个初始值4,后面再扩容时则最大容量翻倍

        第一次调用realloc函数时,由于我们初始化时将指针a赋为空指针,故第一次调用realloc函数作用和malloc函数相当,后面再次调用则实现扩容功能

void SLCheckCapacity(SL* ps)
{
	assert(ps);断言是否为空指针,如传入空指针则报错,防止函数被误用
	if (ps->size == ps->capacity)//判断当前数据个数是否到达最大值,是则增容
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//第一次给值为4,后面则翻倍
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));//利用动态内存管理函数realloc开辟空间
		if (tmp == NULL)//判断是否开辟成功,如果返回空指针说明开辟失败则报错,否则将空间的地址付给a指针
		{
			perror("realloc fail");
			return;
		}
		ps->a = tmp;
		ps->capacity = newCapacity;//最大容量更新为扩容之后的容量
	}
}

3.尾插

        尾插先判断空间是否已满,若空间已满,则需要扩容,然后再直接从尾部插入,后将数据个数加1即可

void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	SLCheckCapacity(ps);//检查是否需要增容
	ps->a[ps->size] = x;//在尾部插入值
	ps->size++;			//数据个数加1
}

4.头插

        头插也需要判断空间是否已满,若空间已满,则需要扩容,然后再从头部插入,插入过程:先将顺序表里面已有的每一个元素往后挪动一个位置,相当于头部就腾出了一个“空位”,然后我们将需要插入的元素放到这个“空位”即可,后将数据元素加1

void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	SLCheckCapacity(ps);//检查是否需要增容
	int end = ps->size - 1;
	while (end >= 0)//从尾部依次挪动元素
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;//将值赋给第一个元素
	ps->size++;  //数据个数加1
}

5.尾删

        尾删需要先判断当前顺序表是否有元素,没有元素则直接报错,如果有元素,我们只需要将数据个数减1即达到删除效果,而不需要对最后一个元素进行操作,后续操作直接将它覆盖就行

void SLPopBack(SL* ps)
{
	assert(ps->size > 0);//判断当前是否有元素
	ps->size--;//直接将数据个数减1即可
}

6.头删

        头删也需要先判断当前顺序表是否有元素,没有元素则直接报错,如果有元素,则删除的过程为:以我们排队打饭为例,当队伍的最前面一个人打完饭,后面的每一个人就都会往前一个位置,此时删除元素也是一样,从第二个位置开始到最后一个元素每个元素都依次往前挪动一个元素即可,后将数据个数减1

void SLPopFront(SL* ps)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	assert(ps->size > 0);//判断当前是否有元素
	
	int begin = 0;
	while (begin < ps->size - 1)//从尾部一次挪动元素
	{
		ps->a[begin] = ps->a[begin+1];
		begin++;
	}
	ps->size--;//数据个数减1
}

7.指定位置插入

        指定位置我们需要先判断指定位置是否合法,如果小于0或者大于最大元素个数则直接报错,再判断是否需要增容,然后从指定位置开始到最后一个元素每个元素依次往后挪动一个位置,然后再将所插入的元素放到指定位置即可,后将数据元素个数加1

void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	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++;//数据个数加1
}

8.指定位置删除

        指定位置删除野需要先判断给定位置是否合法,不合法则直接报错,然后从指定位置到最后一个元素依次往前挪动一个位置即可,后将数据元素减1

void SLErase(SL* ps, int pos)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	assert(pos >= 0 && pos < ps->size);//判断给定的位置是否合法
	int begin = pos;
	while (begin < ps->size - 1)//从指定位置依次挪动元素,直到到达尾部的前一个元素
	{
		ps->a[begin] = ps->a[begin + 1];
		begin++;
	}
	ps->size--;//数据个数减1
}

9.打印

        打印只需要定义一个循环变量,以下标的形式遍历顺序表打印即可

void SLPrint(SL* ps)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	int i = 0;
	for (i = 0; i < ps->size; i++)//依次遍历打印顺序表即可
	{
		printf("%d ", ps->a[i]);
	}
}

10.查找

        查找也是遍历顺序表,将每一个元素与查找的元素比较,若相等则返回元素下标,若遍历完没有找到元素,则返回-1,证明找不到该元素

int SLFind(SL* ps, SLDataType x)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	int i = 0;
	for (i = 0; i < ps->size; i++)//遍历数组,比较是否相等,相等则返回元素下标
	{
		if (ps->a[i] == x)
			return i;
	}
	return -1;//如果遍历没有找到该元素,则返回-1
}

11.销毁

        由于我们前面开辟空间是利用动态内存管理函数realloc开辟的,而该函数开辟的空间是由程序员自行开辟的,空间位于堆上,使用完空间后需要我们手动销毁,否则会导致内存泄露

        销毁空间我们需要用到free函数,我们打开cpp网站查看该函数有关信息

        freea函数的参数是一个指针,即所需要销毁的空间的地址,我们销毁顺序表只需要将指针a传给free函数即可,后讲指针a赋为空指针,防止其成为野指针

void SLDestroy(SL* ps)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	if (ps->a)
	{
		free(ps->a);//释放a指针指向的空间
		ps->a = NULL;//将a指针置为空,防止其成为野指针
		ps->size = ps->capacity = 0;//当前数据元素个数和最大数据元素个数全置为0
	}
}

        可以看到,上面的基本操作都是有相应的接口函数,我们只需要调用相应的函数即可实现顺序表的一些基本操作

        上面所有的接口函数都用到了assert函数,且都位于函数体开头,assert函数称之为断言函数,当表达式为真是继续执行,当表达式为假时则直接报错,而这种报错可以让我们快速了解错误出在什么地方

        我们打开cpp网站查看该函数有关信息

        上面的所有接口函数调用assert函数,传的参数时指针a,当指针a为空指针时则直接报错,可以防止函数被误用而导致一些未知的错误 

        上面就是顺序表的一些基本操作,以下是全部代码:

SeqList.c

#include"SeqList.h"
void SLCheckCapacity(SL* ps)
{
	assert(ps);断言是否为空指针,如传入空指针则报错,防止函数被误用
	if (ps->size == ps->capacity)//判断当前数据个数是否到达最大值,是则增容
	{
		int newCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//第一次给值为4,后面则翻倍
		SLDataType* tmp = (SLDataType*)realloc(ps->a, newCapacity * sizeof(SLDataType));//利用动态内存管理函数realloc开辟空间
		if (tmp == NULL)//判断是否开辟成功,如果返回空指针说明开辟失败则报错,否则将空间的地址付给a指针
		{
			perror("realloc fail");
			return;
		}
		ps->a = tmp;
		ps->capacity = newCapacity;//最大容量更新为扩容之后的容量
	}
}
void SLInit(SL * ps)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	ps->a = NULL;//置为空指针
	ps->size = 0;//初始化为0
	ps->capacity = 0;
}
void SLDestroy(SL* ps)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	if (ps->a)
	{
		free(ps->a);//释放a指针指向的空间
		ps->a = NULL;//将a指针置为空,防止其成为野指针
		ps->size = ps->capacity = 0;//当前数据元素个数和最大数据元素个数全置为0
	}
}
void SLPushBack(SL* ps, SLDataType x)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	SLCheckCapacity(ps);//检查是否需要增容
	ps->a[ps->size] = x;//在尾部插入值
	ps->size++;			//数据个数加1
}
void SLPrint(SL* ps)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	int i = 0;
	for (i = 0; i < ps->size; i++)//依次遍历打印顺序表即可
	{
		printf("%d ", ps->a[i]);
	}
}
void SLPopBack(SL* ps)
{
	assert(ps->size > 0);//判断当前是否有元素
	ps->size--;//直接将数据个数减1即可
}
void SLPushFront(SL* ps, SLDataType x)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	SLCheckCapacity(ps);//检查是否需要增容
	int end = ps->size - 1;
	while (end >= 0)//从尾部依次挪动元素
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;//将值赋给第一个元素
	ps->size++;  //数据个数加1
}
void SLPopFront(SL* ps)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	assert(ps->size > 0);//判断当前是否有元素
	
	int begin = 0;
	while (begin < ps->size - 1)//从尾部一次挪动元素
	{
		ps->a[begin] = ps->a[begin+1];
		begin++;
	}
	ps->size--;//数据个数减1
}
void SLInsert(SL* ps, int pos, SLDataType x)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	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++;//数据个数加1
}
void SLErase(SL* ps, int pos)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	assert(pos >= 0 && pos < ps->size);//判断给定的位置是否合法
	int begin = pos;
	while (begin < ps->size - 1)//从指定位置依次挪动元素,直到到达尾部的前一个元素
	{
		ps->a[begin] = ps->a[begin + 1];
		begin++;
	}
	ps->size--;//数据个数减1
}
int SLFind(SL* ps, SLDataType x)
{
	assert(ps);//断言是否为空指针,如传入空指针则报错,防止函数被误用
	int i = 0;
	for (i = 0; i < ps->size; i++)//遍历数组,比较是否相等,相等则返回元素下标
	{
		if (ps->a[i] == x)
			return i;
	}
	return -1;//如果遍历没有找到该元素,则返回-1
}

SeqList.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
//动态顺序表
typedef int SLDataType;//对类型重定义,方便适应不同的数据类型
typedef struct SeqList
{
	SLDataType *a;//定义指针指向动态开辟的空间
	int size;    //当前存储的数据个数
	int capacity; //数据最大个数
}SL;
void SLCheckCapacity(SL *ps);
void SLInit(SL * ps);
void SLDestroy(SL* ps);
void SLPrint(SL* ps);

void SLPushBack(SL * ps, SLDataType x);
void SLPopBack(SL * ps);

void SLPushFront(SL* ps, SLDataType x);
void SLPopFront(SL* ps);

void SLInsert(SL* ps,int pos, SLDataType x);
void SLErase(SL* ps, int pos);

int SLFind(SL* ps, SLDataType x);

test.c

#define _CRT_SECURE_NO_WARNINGS
#include"SeqList.h"
void TestSeqList()
{
	SL sl;
	SLInit(&sl);
	SLPushBack(&sl, 1);
	SLPushBack(&sl, 2);
	SLPushBack(&sl, 3);
	SLPushBack(&sl, 4);
	SLPushBack(&sl, 5);
	SLPushFront(&sl, 0);
	SLInsert(&sl, 2, 9);
	SLErase(&sl, 2);
	int pos = SLFind(&sl, 5);
	if (pos != -1)
		SLErase(&sl, pos);
	SLPrint(&sl);
	SLDestroy(&sl);
}
int main()
{

	TestSeqList();
	return 0;
}

输出结果:

  好啦,顺序表我们就先学到这里,如果喜欢我的文章,欢迎动动手指一键三连~

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

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

相关文章

IBMMQ教程二(window版安装)

下载下载地址&#xff1a;https://public.dhe.ibm.com/ibmdl/export/pub/software/websphere/messaging/mqadv/我这里选择的是9.1.0.0版本安装将下载完成的压缩包解压双击Setup.exe直接运行点击软件需求查看系统配置是否满足&#xff0c;右边绿色的对号说明满足需求&#xff0c…

linux 端口查询命令

任何知识都是用进废退&#xff0c;有段时间没摸linux&#xff0c;这大脑里的知识点仿佛全部消失了&#xff0c;就无语。 索性&#xff0c;再写一篇记录&#xff0c;加强一下记忆&#xff0c;下次需要就看自己的资料好了。lsof命令Linux端口查询命令可以通过lsof实现&#xff1a…

教育小程序开发解决方案

如今无论是国家还是家庭对于教育的重视性也越来越高&#xff0c;都希望自己的孩子能够赢在起跑线上&#xff0c;但是因为工作的缘故许多家长并没有过多的精力去辅导孩子学习&#xff0c;再加上许多家长对于教育也并没有经验与技巧。而这些都充分体现了正确教育的重要性。 那么一…

2023金三银四常见Handler面试总结,附带答案

以下的Handler的面试题都是在面试过程中总结出来比较常见的面试题&#xff0c;现在分享给大家&#xff0c;希望可以帮助你们&#xff01;1.Handler的实现原理从四个方面看Handler、Message、MessageQueue 和 Looper Handler:负责消息的发送和处理 Message:消息对象&#xff0c;…

FL Studio21最新中文版下载及切换语言教程

随着近年来摇滚、电音的发展&#xff0c;越来越多的人开始对电子音乐编曲感兴趣&#xff0c;而电音编曲的首要条件&#xff0c;就是需要一个好的DAW&#xff08;数字音频工作站&#xff09;&#xff0c;常用的DAW有很多&#xff0c;例如Cubase、Nuendo、Pro Tools、 SONAR等等&…

Unity - 搬砖日志 - Texture.mipmapBias 无效的解决方法

文章目录环境原因解決方案Referenes环境 Unity : 2020.3.37f1 Pipeline : BRP 原因 因为美术发现有些贴图太糊&#xff0c;但是经过研究发现&#xff0c;mipmap0就是完全够精度的 但是不可能还要提升贴图的尺寸&#xff0c;因为经过多方咨询&#xff08;咨询TA大佬&#xff0…

2023 年会是网络安全的关键年吗?

过去 12 个月对网络安全领域和周围的每个人来说再次充满挑战。和往年不同&#xff0c;感觉很不一样&#xff0c;攻击源源不断。过去&#xff0c;大型漏洞每季度发生一次&#xff0c;但在过去一年中&#xff0c;在某些情况下&#xff0c;我们几乎每周都会处理严重漏洞。 已知利…

itop-3568开发板驱动学习笔记(7)高级字符设备(一)阻塞 IO 和 非阻塞 IO

《【北京迅为】itop-3568开发板驱动开发指南.pdf》 学习笔记 文章目录阻塞 IO非阻塞 IOIO 实验&#xff08;使用等待队列&#xff09;等待队列阻塞 IO 实验非阻塞 IO 实验阻塞 IO I/O输入/输出(Input/Output)&#xff0c;分为IO设备和IO接口两个部分。 在POSIX兼容的系统上&…

python学习——【第四弹】

前言 上一篇文章 python学习——【第三弹】 中学习了python中的流程控制语句&#xff0c;这篇文章我们接着学习python中的序列。先给大家介绍不可变序列 字符串和可变序列 列表&#xff0c;下一篇文章接着补充元组&#xff0c;集合和字典。 序列 指的是一块可以存放多个值的…

多线程的风险 --- 线程安全

✨个人主页&#xff1a;bit me&#x1f447; ✨当前专栏&#xff1a;Java EE初阶&#x1f447; ✨每日一语&#xff1a;低头赶路&#xff0c;敬事如仪&#xff1b;自知自心&#xff0c;其路则明。 目 录&#x1f378;一. 线程不安全&#x1f379;二. 线程不安全的原因&#x1f…

【C语言】每日刷题 —— 牛客语法篇(1)

前言 大家好&#xff0c;今天带来一篇新的专栏c_牛客&#xff0c;不出意外的话每天更新十道题&#xff0c;难度也是从易到难&#xff0c;自己复习的同时也希望能帮助到大家&#xff0c;题目答案会根据我所学到的知识提供最优解。 &#x1f3e1;个人主页&#xff1a;悲伤的猪大…

Java的jar包打包成exe应用

将springboot项目使用maven打出的jar包&#xff0c;打成windows平台下exe应用程序包&#xff08;自带jre环境&#xff09;。 工具&#xff1a;1、exe4j 2、Inno Setup 工具放到网盘&#xff0c;链接&#xff1a;https://pan.baidu.com/s/1ZHX8P7u-7GBxaC6uaIC8Ag 提取码&#x…

VMware16pro虚拟机安装全过程

很多时候需要用到Linux系统&#xff0c;简单的一种方式可以是&#xff1a;Windows系统运行Linux&#xff08;Windows Subsystem for Linux&#xff09;不过有些时候还是需要虚拟机来运行Linux&#xff0c;也更方便点&#xff0c;比如在做嵌入式系统的烧录等操作都需要Linux环境…

人的高级认知:位置感

你知道吗&#xff1f;人有个高级认知&#xff1a;位置感 位置感是啥&#xff1f;咋提高位置感&#xff1f; 趣讲大白话&#xff1a;知道自己几斤几两 【趣讲信息科技99期】 ******************************* 位置感 就是对自己所处环境和自身存在的领悟 属于人生智慧 来源于阅历…

设计模式——创建型模型——单列模式(8种实现)

前言&#xff1a; &#x1f44f;作者简介&#xff1a;我是笑霸final&#xff0c;一名热爱技术的在校学生。 &#x1f4dd;个人主页&#xff1a;个人主页1 || 笑霸final的主页2 &#x1f4d5;系列专栏&#xff1a;计算机基础专栏 &#x1f4e7;如果文章知识点有错误的地方&#…

保姆级使用PyTorch训练与评估自己的EfficientNetV2网络教程

文章目录前言0. 环境搭建&快速开始1. 数据集制作1.1 标签文件制作1.2 数据集划分1.3 数据集信息文件制作2. 修改参数文件3. 训练4. 评估5. 其他教程前言 项目地址&#xff1a;https://github.com/Fafa-DL/Awesome-Backbones 操作教程&#xff1a;https://www.bilibili.co…

eps文件删除了能恢复吗?恢复误删eps文件的三种方法

eps文件格式专为矢量图像和图形而设计。虽然没有被广泛使用&#xff0c;但它仍然受到各种插画家和平面设计师的钟爱。eps文件十分适合创建徽标和商标设计&#xff0c;主要应用见于广告牌、海报和横幅。可是在使用设备过程中&#xff0c;难免会遇到数据丢失问题&#xff0c;如果…

KaiwuDB 时序引擎数据存储内存对齐技术解读

一、理论1、什么是内存对齐现代计算机中内存空间都是按照 byte 划分的&#xff0c;在计算机中访问一个变量需要访问它的内存地址&#xff0c;从理论上看&#xff0c;似乎对任何类型的变量的访问都可以从任何地址开始。但在实际情况中&#xff0c;通常在特定的内存地址才能访问特…

并发编程---java锁

java锁一 多线程锁synchronized案例分析1.1synchronized介绍1.2 synchronized案例分析1.2.1.标准访问&#xff0c;请问先打印邮件还是短信&#xff1f;1.2.2.邮件⽅法暂停4秒钟&#xff0c;请问先打印邮件还是短信&#xff1f;分析1.2.3.新增⼀个普通⽅法hello&#xff08;&…

Django系统开发

Django系统开发 1.新建项目 创建Django项目 删除templates目录 删除settings.py里templates -> DIRS的列表数据 2.创建app 在Pycharm中 注册app 在settings.py中找到 INSTALLED_APPS 加入对应路径 app01.apps.App01Config 3.表结构 from django.db import modelsclas…