数据结构之顺序表篇

news2025/8/2 10:33:11

一、顺序表概念
二、顺序表各类接口实现

*顺序表初始化
**顺序表销毁
***顺序表插入操作
****顺序表删除操作
*****顺序表查找操作
******顺序表实现打印操作
三、顺序表整体实现源码
*SeqList.h
**SeqList.c
***test.c


一、顺序表概念

讲顺序表之前先引入线性表概念,线性表是n个有相同特性的数据元素的有限序列,而常见的线性表又有:顺序表、链表、栈、队列、串,而例如图、树就是非线性表;
顺序表概念:顺序表向内存中要了一块连续的空间,然后依次存储数据,就是一个一个的挨着存储,而且里面存放的数据类型是同一种类型,就是c语言中的一维数组。
而顺序表又可分为静态的和动态的,静态顺序表就是给定一个空间,这个空间大小就定死了,不可再修改,那样的话就会造成空间浪费或者空间不足,比如:电梯超重不能运行,就是给定人数为13人,多了就不能升降(当然这只是理论上的);静态顺序表的空间不可改变,因此用动态顺序表比较合适,按照自己的需求向堆中申请空间一次不够再第二次第三次直到申请空间足够,这样不会造成空间过多的浪费。
在顺序表中要实现对数据的各种操作包括增、删、查、改。而其中增和删又可以在尾部,中间,头部进行

二、顺序表的各类接口实现

以下是顺序表存储的结构化以及常用头文件包含

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SDataType;//类型想换就换,不然在后面换时需要每一个都换类型
#define INIT_CAPACITY 4//对最开始空间容量为4
typedef struct SeqList
{
	SDataType *a;//动态分配数组
	int size;//有效数据个数
	int capacity;//数组容量
}SL;

*顺序表初始化代码

void SeqInit(SL* ps)
{
	ps->a = (SDataType*)malloc(sizeof(SDataType)*INIT_CAPACITY);//向堆动态申请内存空间
	if (ps->a == NULL)//但凡申请都有可能失败
	{
		perror("malloc fail");
		return;
	}
	ps->size = 0;//初始条件下数组中没有数据
	ps->capacity = INIT_CAPACITY;//一上来就先给数组4个空间大小
}

**顺序表销毁代码

void SeqDestory(SL* ps)
{
	free(ps->a);//堆中开辟的需要释放
	ps->a = NULL;//释放之后置空
	ps->size = ps->capacity = 0;//空间大小置为0
}

***顺序表插入代码(包含头插,尾插,任意位置插入)
顺序表插入过程就如插队一样,当中午下课后,去食堂排队吃饭,一个挨着一个排好,这时忽然走来一个人,他可以选择就在队伍末尾跟上,也可以在队头和其他位置插入俗称插队,当然在其后面的肯定不安逸,因为他们都要向后挪动一位,这时顺序表插入就比如排队
在这里插入图片描述
顺序表插入算法思路:从最末尾开始向后挪动,直到空出一个位置,然后将数据插入进去,顺序表长度加一
其中空间容量不够需要给它扩容
尾插时间复杂度为O(1)
最坏的情况下,每一个元素都要向后移到,所以时间复杂度为O(n)

当然在顺序表插入数据时需要考虑空间是否足够,以下是对顺序表增容代码
void Checkcpacity(SL* ps)
{
//扩容
if (ps->size == ps->capacity)
{
SDataType* tmp = (SDataType*)realloc(ps->a, sizeof(SDataType) * ps->capacity * 2);//扩容看自己喜欢,但是二倍较为合适
if (tmp == NULL)
{
printf(“realloc fail”);
exit(-1);
}

	ps->capacity *= 2;
	ps->a = tmp;//将新开辟的空间给数组a
}

}

*尾插代码

void SeqPushBack(SL* ps, SDataType x)
{
	扩容
	//if (ps->size == ps->capacity)
	//{
	//	SDataType* tmp = (SDataType*)realloc(ps->a, sizeof(SDataType) *ps->capacity*2);//扩容看自己喜欢,但是二倍较为合适
	//	if (tmp == NULL)
	//	{
	//		printf("realloc fail");
	//		exit(-1);
	//	}

	//	ps->capacity *= 2;
	//	ps->a = tmp;//将新开辟的空间给数组a
	//}

	Checkcpacity(ps);

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

头插代码

void SeqPushFront(SL* ps, SDataType x)
{
	assert(ps);
	Checkcpacity(ps);
	int begin = 0;
	int end = ps->size;
	while (end >= 0)
	{
		ps->a[end] = ps->a[end - 1];
		end--;
	}

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



}

任意位置插入

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

	int end = ps->size;
	while (end > pos)
	{
		ps->a[end] = ps->a[end - 1];
		end--;
	}

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

****顺序表删除操作
也包括头删尾删和任意位置删除,删除可以理解为是后一个把前一个覆盖,然后顺序表长度减一
在这里插入图片描述
删除算法在末尾删时间复杂度就是最好的情况为O(1),它不必循环
最坏的情况是在头部删除,删除一个就要挪动n-1个数据,其时间复杂度为O(N),删除操作的时间复杂度就为O(n)

头删

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

	ps->size--;

}
**``尾删**

```c
void SeqPopBack(SL* ps)
{/*
	if (ps->size == 0)
	{
		return;
	}*/


	assert(ps->size > 0);//断言可以让你知道是哪里出了问题
	ps->size--;
}

任意位置删除

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

	while (pos < ps->size-1)
	{
		ps->a[pos] = ps->a[pos + 1];
		pos++;
	}

	ps->size--;

}

*****顺序表查找与修改操作
查找

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

	return -1;
}

修改

void SeqModify(SL* ps, int pos, SDataType x)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (i == pos)
		{
			ps->a[i] = x;
		}
	}
}

******顺序表打印

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

	printf("\n");
}

****三、顺序表整体实现源码
SeqList.h

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


#define INIT_CAPACITY 4//初始容量
typedef int SDataType;//类型想换就换,不然在后面换时需要每一个都换类型

typedef struct SeqList
{
	SDataType *a;
	int size;//有效数据个数
	int capacity;//空间容量不够考虑扩容
}SL;

void SeqInit(SL* ps);//顺序表初始化

void SeqDestory(SL* ps);//顺序表销毁

void Seqprint(SL* ps);//顺序表输出

void SeqPushBack(SL* ps, SDataType x);//尾插

void SeqPopBack(SL* ps);//尾删

void SeqPushFront(SL* ps, SDataType x);//头插

void SeqPopFront(SL* ps);//头删

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

void SeqInsert(SL* ps, int pos, SDataType x);//在pos位置插入x

int SeqFind(SL* ps, SDataType x);//查找值为x的位置

void SeqModify(SL* ps, int pos, SDataType x);//修改

SeqList.c

#include"SeqList.h"

void SeqInit(SL* ps)
{
	ps->a = (SDataType*)malloc(sizeof(SDataType)*INIT_CAPACITY);
	if (ps->a == NULL)
	{
		perror("malloc fail");
		return;
	}
	ps->size = 0;
	ps->capacity = INIT_CAPACITY;
}

void SeqDestory(SL* ps)
{
	free(ps->a);//堆中开辟的需要释放
	ps->a = NULL;//释放之后置空
	ps->size = ps->capacity = 0;//空间大小置为0
}

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

	printf("\n");
}

void Checkcpacity(SL* ps)
{
	//扩容
	if (ps->size == ps->capacity)
	{
		SDataType* tmp = (SDataType*)realloc(ps->a, sizeof(SDataType) * ps->capacity * 2);//扩容看自己喜欢,但是二倍较为合适
		if (tmp == NULL)
		{
			printf("realloc fail");
			exit(-1);
		}

		ps->capacity *= 2;
		ps->a = tmp;//将新开辟的空间给数组a
	}
}


void SeqPushBack(SL* ps, SDataType x)
{
	扩容
	//if (ps->size == ps->capacity)
	//{
	//	SDataType* tmp = (SDataType*)realloc(ps->a, sizeof(SDataType) *ps->capacity*2);//扩容看自己喜欢,但是二倍较为合适
	//	if (tmp == NULL)
	//	{
	//		printf("realloc fail");
	//		exit(-1);
	//	}

	//	ps->capacity *= 2;
	//	ps->a = tmp;//将新开辟的空间给数组a
	//}

	Checkcpacity(ps);

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

void SeqPopBack(SL* ps)
{/*
	if (ps->size == 0)
	{
		return;
	}*/


	assert(ps->size > 0);//断言可以让你知道是哪里出了问题
	ps->size--;
}

void SeqPushFront(SL* ps, SDataType x)
{
	assert(ps);
	Checkcpacity(ps);
	int begin = 0;
	int end = ps->size;
	while (end >= 0)
	{
		ps->a[end] = ps->a[end - 1];
		end--;
	}

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



}

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

	ps->size--;

}

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

	int end = ps->size;
	while (end > pos)
	{
		ps->a[end] = ps->a[end - 1];
		end--;
	}

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

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

	while (pos < ps->size-1)
	{
		ps->a[pos] = ps->a[pos + 1];
		pos++;
	}

	ps->size--;

}

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

	return -1;
}

void SeqModify(SL* ps, int pos, SDataType x)
{
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (i == pos)
		{
			ps->a[i] = x;
		}
	}
}

test.c

#include"SeqList.h"

void test()
{
	SL s;
	SeqInit(&s);//传结构体地址过去,形参改变实参
	SeqPushBack(&s, 1);
	SeqPushBack(&s, 2);
	SeqPushBack(&s, 3);
	SeqPushBack(&s, 4);
	SeqPushBack(&s, 5);
	Seqprint(&s);
	/*SeqPopBack(&s);
	SeqPopBack(&s);
	SeqPopBack(&s);
	SeqPopBack(&s);
	Seqprint(&s);
	SeqPopBack(&s);
	SeqPopBack(&s);
	SeqPopBack(&s);
	Seqprint(&s)*/;

	SeqPushFront(&s, 9);
	Seqprint(&s);
	/*SeqPopFront(&s);
	SeqPopFront(&s);
	SeqPopFront(&s);
	SeqPopFront(&s);*/
	//SeqPopFront(&s);
	//SeqPopFront(&s);
	//SeqPopFront(&s);
	//SeqPopFront(&s);
	//SeqPopFront(&s);
	//SeqPopFront(&s);
	//SeqPopFront(&s);
	SeqPopFront(&s);
	//SeqPopFront(&s);
	//Seqprint(&s);
	SeqInsert(&s, 3, 10);
	Seqprint(&s);

	SeqErase(&s, 3);
	Seqprint(&s);

	int pos = SeqFind(&s, 3);
	printf("%d\n", pos);

	if (pos != -1)
	{
		SeqModify(&s, pos, 10);
	}

	Seqprint(&s);
	SeqDestory(&s);
}

int main()
{
	test();

	return 0;
}

总结

顺序表有优点也有缺点
优点:尾插、尾删效率贼高,也可以按下表来访问顺序表中的元素
缺点:在顺序表中出了尾部上的插入删除外,在其他位置删除或者插入效率都极低,而且在空间不够扩容的时候容易造成空间浪费
好了数据结构顺序表篇就结束了,球球各位佬们一键四练叭!你们的支持对于我来说尤为重要

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

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

相关文章

可视化服务编排在金融APP中的实践

本文重点介绍了京东金融APP在BFF层实践过程中遇到的问题&#xff0c;并引出可视化服务编排在金融APP中的落地实践&#xff0c;其中重点介绍了可视化服务编排系统的核心功能及实现。 可视化服务编排系统已经稳定支持了金融APP从去年618到现在的所有发版迭代&#xff0c;对人效提…

Apache ActiveMQ安装和使用

文章目录Apache ActiveMQ安装和使用 环境下载安装配置启动登录Apache ActiveMQ安装和使用 环境 Ubuntu20.04 下载 官网&#xff1a;https://activemq.apache.org/download-archives 如下载5.14.4版本&#xff0c;apache-activemq-5.14.4-bin.tar.gz&#xff0c;测试过没问题…

分布式算法 - 一致性Hash算法

一致性Hash算法是个经典算法&#xff0c;Hash环的引入是为解决单调性(Monotonicity) 的问题&#xff1b;虚拟节点的引入是为了解决 平衡性(Balance) 问题。一致性Hash算法引入在分布式集群中&#xff0c;对机器的添加删除&#xff0c;或者机器故障后自动脱离集群这些操作是分布…

MySQL索引类型及原理?一文读懂

一、什么是MySQL索引&#xff1f; MySQL索引是一种数据结构&#xff0c;用于提高数据库查询的性能。它类似于一本书的目录&#xff0c;通过在表中存储指向数据行的引用&#xff0c;使得查询数据的速度更快。 在MySQL中&#xff0c;索引通常是在表上定义的&#xff0c;它们可以…

本地新创建的项目,关联/上传到码云

以下示例以mac为例&#xff0c;window将相关步骤改为windows对应的操作即可1、打开终端&#xff0c;通过终端命令 cd 切换到新建的本地项目目录下&#xff0c;如&#xff1a;&#xff08;/Users/wangcongming/Documents/TuoTuo/mobile_acitvity 为我的新建项目地址&#xff09;…

使用 ChatGPT ,通过自然语言编写 eBPF 程序和追踪 Linux 系统

eBPF 是一项革命性的技术&#xff0c;起源于 Linux 内核&#xff0c;可以在操作系统的内核中运行沙盒程序。它被用来安全和有效地扩展内核的功能&#xff0c;而不需要改变内核的源代码或加载内核模块。今天&#xff0c;eBPF被广泛用于各类场景&#xff1a;在现代数据中心和云原…

「RISC-V Arch」SBI 规范解读

术语 SBI&#xff0c;Supervisor Binary Interface&#xff0c;管理二进制接口 U-Mode&#xff0c;User mode&#xff0c;用户模式 S-Mode&#xff0c;Supervisor mode&#xff0c;监督模式 VS-Mode&#xff0c;Virtualization Supervisor mode&#xff0c;虚拟机监督模式 …

嵌入式 Linux Shell编程

目录 1、shell脚本 2、执行shell脚本 3、shell脚本编写 3.1 shell变量 3.2 标准变量或环境变量 3.4 变量赋值有五种格式 3.5 运算符和表达式 关系运算符 布尔运算符 3.6 Test命令用法 1、判断表达式 2、判断字符串 3.判断整数 4、判断文件 3.7 数组 1、数组定义…

什么是 RPA ?What is robotic process automation (RPA)?

目录 前言 What is a business process? 什么是业务流程? What does "robotic process automation" mean?“机器人过程自动化”是什么意思? What is robotic process automation (RPA)?什么是机器人流程自动化 (RPA)? What

SGI 空间配置器

前言 空间配置器是 STL 六大组件之一&#xff0c;它总是隐藏在容器的背后&#xff0c;默默工作&#xff0c;默默付出。本文为《STL 源码剖析》读书笔记&#xff0c;主要讨论 SGI 版本空间的配置和释放&#xff0c;对代码进行解读时会改变一些写法&#xff0c;使其更易于阅读。…

__stack_chk_fail问题分析

一、问题进程收到SIGABRT信号异常退出&#xff0c;异常调用栈显示__stack_chk_fail*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** Build fingerprint: Pico/A7H10/PICOA7H10:10/5.5.0/smartcm.1676912090:userdebug/dev-keys Revision: 0 ABI: arm64 Times…

VS Code下载安装教程

VS Code下载安装使用教程 目录VS Code下载安装使用教程一、下载二、安装三、使用教程3.1 VS Code中的第一个页面HelloWorld.html3.2 VS Code插件安装3.2.1 安装中文界面3.2.3 安装 Open in Browser插件3.2.4 安装Auto Rename Tag插件注意&#xff1a;3.3 code .命令&#xff0c…

EasyNLP集成K-Global Pointer算法,支持中文信息抽取

作者&#xff1a;周纪咏、汪诚愚、严俊冰、黄俊 导读 信息抽取的三大任务是命名实体识别、关系抽取、事件抽取。命名实体识别是指识别文本中具有特定意义的实体&#xff0c;包括人名、地名、机构名、专有名词等&#xff1b;关系抽取是指识别文本中实体之间的关系&#xff1b;…

代码随想录算法训练营第十天 | 理论基础、232.用栈实现队列、225. 用队列实现栈

打卡第10天&#xff0c;今天学习栈和队列 今日任务 理论基础232.用栈实现队列 用队列实现栈 理论基础 栈&#xff1a;先进后出 队列&#xff1a;先进先出 栈和队列是STL&#xff08;C标准库&#xff09;里面的两个数据结构 在 SGI STL 中&#xff0c;栈和队列的底层实现 栈…

Android使用FrameLayout+RecyclerView实现悬浮置顶封装功能

一、实际开发效果图默认效果:滚动后的效果:二、效果实现方式CoordinatorLayout AppBarLayout RecyclerView(适用于简单的悬浮View不超过一屏的情况&#xff0c;头部固定&#xff0c;数据简单)FrameLayout RecyclerView(适用于复杂的多条目布局&#xff0c;且悬浮条目位置受后…

移动硬盘无法识别?恢复硬盘,问题已解决

移动硬盘和U盘比较&#xff0c;它的体积是比较大的&#xff0c;但是相应的存储位置就会大点。它作为可移动设备&#xff0c;对于存储大型的数据&#xff0c;还是非常方便的。 有时候用户会发现移动硬盘出现一些问题&#xff0c;移动硬盘与电脑连接后&#xff0c;在电脑桌面右下…

java自定义注解实现数据字典映射

一 &#xff1a;前言 在我们开发过程中&#xff0c;我们从前端页面接收的数据字典一般都是key&#xff08;大多数为数字&#xff09;&#xff0c;但我们在页面显示的时候&#xff0c;想用其value值。如果我们每使用一次就要去写一些重复的代码去查询&#xff0c;这样会使我们的…

SharePoint Online CDN简介

前言 可能很多人并不了解CDN这个概念&#xff0c;不过作为Web从业人员着实不该&#xff0c;CDN就是内容分发网络&#xff0c;说白了就是第三方帮你托管静态资源&#xff0c;你可以在全球任何位置快速访问到对应的节点的资源。 正文 我们提到的SharePoint CDN&#xff0c;其实更…

高精度加减乘除

高精度加法 对于给定的两个特别大的数我们用两个字符串来接收 s1和s2。 例如&#xff1a;对于两个数 56215455和95425453&#xff0c;即 s1 "56215455" &#xff0c; s2 "95425453"。 对于这两个数&#xff0c;分别用两个列表 a和b来接收(例如&#x…

LeetCode-78. 子集

题目来源 78. 子集 题目思路 其实子集也是一种组合问题&#xff0c;因为它的集合是无序的&#xff0c;子集{1,2} 和 子集{2,1}是一样的。 那么既然是无序&#xff0c;取过的元素不会重复取&#xff0c;写回溯算法的时候&#xff0c;for就要从startIndex开始&#xff0c;而在这…