【数据结构初阶】二、顺序表的实现

news2025/1/4 4:50:33

目录

 一、线性表

二、顺序表 

2.1 顺序表概念及结构

2.2 顺序表接口实现

2.2.1 顺序表初始化

2.2.2 顺序表的销毁

2.2.3 顺序表的打印

2.2.4 顺序表增加数据(插入,头插、尾插)

2.2.5 顺序表删除数据(删除,头删、尾删)

2.2.6 顺序表查找数据

2.2.7 顺序表修改数据

三、顺序表完整代码(C语言)

3.1 SeqList.h

3.2 SeqList.c

3.3 Test.c

 四、顺序表的优缺点


 一、线性表

 在学习顺序表和链表之前,先要了解什么是线性表:

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

文章所讲述的顺序表和下一篇链表便是线性表的一种。

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

例如:顺序表和链表 

顺序表在逻辑结构上是连续的,物理结构上也是连续的;

链表在逻辑结构上是连续的,但是在物理结构上不是连续的。

 -------------------我是分割线------------------  

二、顺序表 

2.1 顺序表概念及结构

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

顺序表一般可以分为:静态顺序表、动态顺序表 

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

#define N 100//对空间大小进行了限定
typedef int SLDataType;便于修改存储的数据类型
typedef struct SeqList
{
	SLDataType arr[N];//定义需要的数组长度
	int size;//记录数组的有效个数(已使用)
}SL;
//缺陷:空间给小了不够用,给大了可能浪费,不实用

  

(2)动态顺序表:使用动态开辟的数组存储

typedef int SLDataType;//便于修改存储的数据类型
typedef struct SeqList
{
	SLDataType* arr;//指向动态开辟的数组,用于存放数据。空间不够则增容
	int size;//数组的个数
	int capacity;//容量大小
}SL;

2.2 顺序表接口实现

首先,我们要创建一个顺序表类型,该顺序表类型包括了顺序表的起始位置、记录顺序表内已有元素个数的计数器(size),以及记录当前顺序表的容量的变量(capacity),这里实现的是动态顺序表

typedef int SLDataType;//便于修改存储的数据类型
//顺序表的动态储存
typedef struct SeqList
{
	SLDataType* arr;//指向动态开辟的数组,用于存放数据
	int size;//数组的个数
	int capacity;//容量大小
}SL;

2.2.1 顺序表初始化

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

2.2.2 顺序表的销毁

顺序表所用的内存空间是动态开辟在堆区的,所以我们在使用完后需要及时对其进行释放,避免造成内存泄漏

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

2.2.3 顺序表的打印

遍历即可

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

2.2.4 顺序表增加数据(插入,头插、尾插)

        每次需要增加数据的时候,首先都应该先检查顺序表内元素个数是否已达顺序表容量上限。若已达上限,那么我们就需要先对顺序表进行扩容,然后才能增加数据。

(1)插入:就是从两个数据中间直接直接插入一个新的数据(时间复杂度为O(n))

//插入
void SeqListInsert(SL* ps, int pos, SLDataType n)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	CheckCapacity(ps);//检查顺序表容量,不够则开辟新空间
	//挪动数据
	int end = ps->size - 1;
	while (end >= pos);
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[pos] = n;
	ps->size++;
}

检查容量需要频繁使用,可以直接封装成一个函数,方便使用

//检查顺序表容量
void CheckCapacity(SL* ps)
{
	assert(ps);
	//进行扩容,两种情况,1、没有开辟空间  2、空间不足
	if (ps->size == ps->capacity)
	{
		int NewCapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2);
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, NewCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			//return;
			exit(-1);
		}
		ps->arr = tmp;
		ps->capacity = NewCapacity;
	}
}

(2)头插:顾名思义就是从头部插入一个新的数据(时间复杂度为O(n))

 这里有两种写法,推荐可以直接复用插入的代码

//顺序表的头插
void SeqListPushFront(SL* ps, SLDataType n)
{
	/*assert(ps);
	CheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[0] = n;
	ps->size++;*/
	//两种都行,下面这种比较方便
	SeqListInsert(ps, 0, n);
}

(3)尾插:这个比较简单,直接从尾上插入即可(时间复杂度为O(1))

 这里也是有两种写法,推荐可以直接复用插入的代码

//尾插
void SeqListPushBack(SL* ps, SLDataType n)
{
	/*assert(ps);
	CheckCapacity(ps);
	ps->arr[ps->size] = n;
	ps->size++;*/
	//两种都行,下面这种比较方便
	SeqListInsert(ps, ps->size, n);
}

2.2.5 顺序表删除数据(删除,头删、尾删)

删除数据,其实可以理解为:从某个位置开始,数据依次向前覆盖。这样一来,该位置的数据就相当于删除了。

(1)删除: 直接删除 pos 位置的值,向前覆盖(时间复度为O(n))

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

	ps->size--;
}

(2)头删(时间复杂度为O(n))

这里也是有两种写法,这里也是有两种写法,推荐可以直接复用删除的代码

//头删, O(n)
void SeqListPopFront(SL* ps)
{
	/*assert(ps);
	assert(ps->size > 0);
	int begin = 1;
	while (begin < ps->size)
	{
		ps->arr[begin - 1] = ps->arr[begin];
		begin++;
	}
	ps->size--;*/
	//两种都行,下面这种比较方便
	SeqListErase(ps, 0);
}

 (3)尾删(时间复杂度为O(1))

 这里也是有两种写法,推荐可以直接复用删除的代码

//尾删
void SeqListPopBack(SL* ps)
{
	/*assert(ps);
	assert(ps->size > 0);
	ps->size--;*/
	//两种都行,下面这种比较方便
	SeqListErase(ps, ps->size - 1);
}

2.2.6 顺序表查找数据

查找数据也相对简单,直接遍历一次顺序表即可,若找到了目标数据,则停止遍历,并返回该数据的下标

//查找数据
int SeqListFind(SL* ps, SLDataType n)
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == n)
		{
			return n;//找到了
		}
	}
	return -1; //找不到
}

2.2.7 顺序表修改数据

修改数据,就直接对该位置的数据进行再次赋值即可。

//修改数据
void SeqListModify(SL* ps, int pos, SLDataType n)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	ps->arr[pos] = n;
}

 -------------------我是分割线------------------ 

三、顺序表完整代码(C语言)

分三个文件写

  1. SeqList.h(类型定义、接口函数声明、引用的头文件)
  2. SeqList.c(接口函数的实现)
  3. Test.c(主函数、测试顺序表各个接口功能)

3.1 SeqList.h

#pragma once//防止头文件被二次引用
//声明
#define _CRT_SECURE_NO_WARNINGS//vs编译器需要,可自行删去
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

typedef int SLDataType;//便于修改存储的数据类型
//顺序表的动态储存
typedef struct SeqList
{
	SLDataType* arr;//指向动态开辟的数组,用于存放数据
	int size;//数组的个数
	int capacity;//容量大小
}SL;

//初始化顺序表
void SeqListInit(SL* ps);
//打印
void SeqListPrint(SL* ps);
//检查顺序表容量
void CheckCapacity(SL* ps);
//销毁顺序表
void SeqListDestroy(SL* ps);

//增
//顺序表的头插,O(n)
void SeqListPushFront(SL* ps, SLDataType n);
//尾插,O(1)
void SeqListPushBack(SL* ps, SLDataType n);
//插入数据
void SeqListInsert(SL* ps, int pos, SLDataType n);

//删
//头删, O(n)
void SeqListPopFront(SL* ps);
//尾删, O(1)
void SeqListPopBack(SL* ps);
//删除数据
void SeqListErase(SL* ps, int pos);

//查找数据
int SeqListFind(SL* ps, SLDataType n);
//修改数据
void SeqListModify(SL* ps, int pos, SLDataType n);

3.2 SeqList.c

//函数接口实现
#include "SeqList.h"

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

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


//检查顺序表容量
void CheckCapacity(SL* ps)
{
	assert(ps);
	//进行扩容,两种情况,1、没有开辟空间  2、空间不足
	if (ps->size == ps->capacity)
	{
		int NewCapacity = (ps->capacity == 0 ? 4 : ps->capacity * 2);
		SLDataType* tmp = (SLDataType*)realloc(ps->arr, NewCapacity * sizeof(SLDataType));
		if (tmp == NULL)
		{
			printf("realloc fail\n");
			//return;
			exit(-1);
		}
		ps->arr = tmp;
		ps->capacity = NewCapacity;
	}
}

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

//顺序表的头插
void SeqListPushFront(SL* ps, SLDataType n)
{
	/*assert(ps);
	CheckCapacity(ps);
	int end = ps->size - 1;
	while (end >= 0)
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[0] = n;
	ps->size++;*/
	//两种都行,下面这种比较方便
	SeqListInsert(ps, 0, n);
}

//尾插
void SeqListPushBack(SL* ps, SLDataType n)
{
	/*assert(ps);
	CheckCapacity(ps);
	ps->arr[ps->size] = n;
	ps->size++;*/
	//两种都行,下面这种比较方便
	SeqListInsert(ps, ps->size, n);
}

//插入
void SeqListInsert(SL* ps, int pos, SLDataType n)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	CheckCapacity(ps);//检查顺序表容量,不够则开辟新空间
	//挪动数据
	int end = ps->size - 1;
	while (end >= pos);
	{
		ps->arr[end + 1] = ps->arr[end];
		end--;
	}
	ps->arr[pos] = n;
	ps->size++;
}

//头删, O(n)
void SeqListPopFront(SL* ps)
{
	/*assert(ps);
	assert(ps->size > 0);
	int begin = 1;
	while (begin < ps->size)
	{
		ps->arr[begin - 1] = ps->arr[begin];
		begin++;
	}
	ps->size--;*/
	//两种都行,下面这种比较方便
	SeqListErase(ps, 0);
}

//尾删
void SeqListPopBack(SL* ps)
{
	/*assert(ps);
	assert(ps->size > 0);
	ps->size--;*/
	//两种都行,下面这种比较方便
	SeqListErase(ps, ps->size - 1);
}

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

	ps->size--;
}


//查找数据
int SeqListFind(SL* ps, SLDataType n)
{
	assert(ps);
	int i = 0;
	for (i = 0; i < ps->size; i++)
	{
		if (ps->arr[i] == n)
		{
			return n;//找到了
		}
	}
	return -1; //找不到
}

//修改数据
void SeqListModify(SL* ps, int pos, SLDataType n)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	ps->arr[pos] = n;
}

3.3 Test.c

//测试函数
#include "SeqList.h"

void SeqListTest1()
{
	SL s1;//定义一个结构体
	SeqListInit(&s1);//初始化
	SeqListPushFront(&s1, 1);
	SeqListPushBack(&s1, 2);
	SeqListPushBack(&s1, 3);
	SeqListPrint(&s1);
	SeqListPopFront(&s1);
	SeqListPrint(&s1);
	SeqListDestroy(&s1);
}
void SeqListTest2()
{
	SL s1;
	SeqListInit(&s1);
	SeqListPushFront(&s1, 1);
	SeqListPushBack(&s1, 2);
	SeqListPushBack(&s1, 3);
	SeqListPushFront(&s1, 0);
	SeqListPushBack(&s1, 4);


	SeqListPrint(&s1);
	SeqListPopBack(&s1);
	SeqListPrint(&s1);

	SeqListDestroy(&s1);
}

void SeqListTest3()
{
	SL s1;
	SeqListInit(&s1);
	SeqListPushFront(&s1, 1);
	SeqListPushBack(&s1, 2);
	SeqListPushBack(&s1, 3);
	SeqListPrint(&s1);
	int find = SeqListFind(&s1, 1);
	if (find == -1)
		printf("找不到\n");
	else
		printf("%d", find);
}

void SeqListTest4()
{
	SL s1;
	SeqListInit(&s1);
	SeqListPushFront(&s1, 1);
	SeqListPushBack(&s1, 2);
	SeqListInsert(&s1, 2, 3);
	SeqListPrint(&s1);

}

int main()
{
	SeqListTest1();
	return 0;
}

 四、顺序表的优缺点

(1)优点

  • 空间连续,可以按下标进行随机访问
  • 顺序表的 cpu 高速缓存命中率高

 (2)缺点

  • 空间不够需要增容,增容有一定的性能消耗,且可能存在一定的空间浪费
  • 增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为100,满了以后增容到200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了95个数据空间。
  • 中间或头部的插入、删除,需要挪动数据,效率低,时间复杂度为O(N)

-------------------我是分割线------------------

文章就到这里

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

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

相关文章

Uniapp集成腾讯IM+音视频通话

腾讯IM(包含界面)源码下载相关配置 传送门&#xff1a;https://cloud.tencent.com/document/product/269/36887 传送门&#xff1a;https://github.com/TencentCloud/TIMSDK/tree/master/uni-app vue2 vue3都可 笔者用的vue2 解压文件 拖到编辑器 #项目右键 在命令行窗口打开 …

Promethues原理详解

目录 引言 一、Prometheus概念 1.1、什么是Prometheus 1.2、Zabbix和Prometheus区别 1.3、Prometheus的特点 二、运维监控平台设计思路 三、Prometheus监控体系 3.1、系统层监控&#xff08;需要监控的数据&#xff09; 3.2、中间件及基础设施类监控 3.3、应用层监控…

语音合成经典模型结构介绍

(以下内容搬运自 PaddleSpeech) Models introduction TTS system mainly includes three modules: Text Frontend, Acoustic model and Vocoder. We introduce a rule-based Chinese text frontend in cn_text_frontend.md. Here, we will introduce acoustic models and voc…

XDataverse免费的统一数据库管理工具

XDataverse产品简介 XDataverse是一款通用的数据库管理工具&#xff0c;主要管理关系型数据库&#xff0c;同时也支持一些其余类型的数据库&#xff0c;比如Redis。其主要功能有 支持主流关系型数据库的常规操作&#xff0c;比如MySQL,SQLServer,SQlite,SQLCE&#xff0c;Postg…

机器学习 逻辑回归(2)softmax回归多类别分类-鸢尾花案例

机器学习 逻辑回归之softmax回归多类别分类-鸢尾花案例一、前言二、假设函数三、One-Hot 独热编码四、代价函数五、梯度下降六、原生代码实现6.1 加载并查看数据6.2 添加前置与数据分割6.3 迭代训练6.4 验证数据七、sklearn代码实现八、参考资料PS&#xff1a;softmax回归损失函…

[时间序列预测]基于BP、LSTM、CNN-LSTM神经网络算法的单特征用电负荷预测[保姆级手把手教学]

系列文章目录 深度学习原理-----线性回归梯度下降法 深度学习原理-----逻辑回归算法 深度学习原理-----全连接神经网络 深度学习原理-----卷积神经网络 深度学习原理-----循环神经网络&#xff08;RNN、LSTM&#xff09; 时间序列预测-----基于BP、LSTM、CNN-LSTM神经网络…

安卓开发Android studio学习笔记14:用户注册登录(案例演示)

Android studio学习笔记第一步&#xff1a;配置activity_information.xml第二步&#xff1a;配置activity_registration.xml第三步&#xff1a;配置strings.xml第四步&#xff1a;配置InformationActivity第五步&#xff1a;配置RegistrationActivity第六步&#xff1a;运行结果…

二叉搜索树

文章目录二叉搜索树1. 概念2. 模拟实现二叉搜索树2.1 准备工作 创建类2.2 查找方法2.3 插入方法2.4 删除方法3. 性能分析二叉搜索树 前言 &#xff1a; 1. 概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不…

学点高端技术:基于密度的聚类算法——FDBSCAN算法

机器学习、人工智能各类KNN算法层出不穷&#xff0c;DBSCAN具有强代表性&#xff0c;它是一个基于密度的聚类算法&#xff0c;最大的优点是能够把高密度区域划分为簇&#xff0c;能够在高噪声的条件下实现对目标的精准识别&#xff0c;但该算法当前已远不能满足人们对于高效率、…

零基础自学javase黑马课程第二天

零基础自学javase黑马课程第二天 ✨欢迎关注&#x1f5b1;点赞&#x1f380;收藏⭐留言✒ &#x1f52e;本文由京与旧铺原创&#xff0c;csdn首发&#xff01; &#x1f618;系列专栏&#xff1a;java学习 &#x1f4bb;首发时间&#xff1a;&#x1f39e;2022年10月16日&#…

【电子技术基础(精华版)】直流稳压电路

前期我们了解了一些关于直流稳压电源的基础知识&#xff0c;为了更好地完善职教高考电子技术专业的需求&#xff0c;接下来我会更新【电子技术基础&#xff08;精华版&#xff09;】&#xff0c;从中可以让更多的职教高考生有效地复习。 由于本人是山东省的一位博主&#xff0…

3、SySeVR测试(上)

一、准备 1、将测试代码放在/home/test目录下&#xff1b; 2、将测试数据导入joern 在/home/SySeVR/joern-0.3.1查看是否存在.joernIndex文件&#xff0c;有的话&#xff0c;需要删除。 删除之后&#xff0c;将测试数据导入joern: java -jar /home/SySeVR/joern-0.3.1/bin/jo…

程序员的中年危机:那些能工作到45、50、60的程序员们,究竟具备了哪些能力?

程序员行业新技术发展迅猛&#xff0c;可以说是日新月异。也正是这个原因&#xff0c;中年危机成为我们必须面对和攻克的问题。 思考一个问题&#xff1a;那些能工作到45、50、甚至60的程序员们&#xff0c;究竟具备了哪些过人的能力&#xff1f; 就我过去的经历和观察来说&a…

A comprehensive overview of knowledge graph completion

摘要 知识图(KG)以其代表和管理海量知识的独特优势&#xff0c;为各种下游知识感知任务(如推荐和智能问答)提供了高质量的结构化知识。KGs的质量和完整性在很大程度上决定了下游任务的有效性。但由于知识产权制度的不完备性&#xff0c;知识产权制度中仍有大量有价值的知识缺失…

【《机器人技术》复习】

【《机器人技术》复习】1. 要求&#xff1a;2. 机械手运动解算问题2.1 自由度考点2.2 运动学方程2.3 动力学方程2.4 传感器2.5 编程题1. 要求&#xff1a; 本次大作业上交截止时间 之前&#xff0c;超时&#xff0c;本门课程判定不及格。 作业上交的格式如下 一律以 WORD 文档…

2022年江西省职业院校技能大赛“网络空间安全”比赛任务书

2022年江西省职业院校技能大赛“网络空间安全” 比赛任务书 一、竞赛时间 总计&#xff1a;360分钟 竞赛阶段竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A模块 A-1 登录安全加固 180分钟 200分 A-2 本地安全策略配置 A-3 流量完整性保护 A-4 事件监控 A-5 …

求交叉链表头结点-面试必备

这里分享一下一个交叉链表的关键题目&#xff0c;觉得不错的小伙伴别忘了点赞支持 交叉链表无环链表思路代码有环链表思路代码总结无环链表 已知有两个链表&#xff08;无环&#xff09;相交&#xff0c;求出相交的头结点 思路 因为链表相交&#xff0c;所以最后一部分一定重…

每天五分钟机器学习:常用的参数寻优方法——k折交叉验证

本文重点 本文我们介绍一种常用的参数寻优方法--k折交叉验证&#xff0c;现在的数据集一般分为三类&#xff0c;分别为训练集&#xff0c;验证集&#xff0c;测试集。训练集用于训练模型&#xff0c;验证集用于调参&#xff0c;测试集用于测试调参之后的模型效果。 但是很多时…

SpringBoot+Vue实现前后端分离社区疫苗接种管理系统

文末获取源码 开发语言&#xff1a;Java 使用框架&#xff1a;spring boot 前端技术&#xff1a;JavaScript、Vue 、css3 开发工具&#xff1a;IDEA/MyEclipse/Eclipse、Visual Studio Code 数据库&#xff1a;MySQL 5.7/8.0 数据库管理工具&#xff1a;phpstudy/Navicat JDK版…

xray和burp联动

目录 xray下载安装CT Stack 安全社区 Burp和xray联动 xray下载安装下载地址&#xff1a;CT Stack 安全社区 先通过PowerShell打开xray所在的目录&#xff0c;运行&#xff0c;生成yaml文件 genca在目录下生成证书 生产证书后将证书导入浏览器 导入后在本地安装一下 Burp和xray…