数据结构:顺序表(C实现)

news2024/11/14 16:39:58

在这里插入图片描述

个人主页 水月梦镜花
个人专栏 C语言 ,数据结构


文章目录

  • 一、顺序表
  • 二、实现思路
    • 1.存储结构
    • 2.初始化顺序表(SeqListInit)
    • 3.销毁顺序表(SeqListDestroty)
    • 4.打印顺序表(SeqListPrint)
    • 5.顺序表尾插(SeqListPushBack)and检查容量(SeqListCheckCapacity)
    • 6.顺序表头插(SeqLsitPushFront)
    • 7.顺序表尾删(SeqListPopBack)
    • 8.顺序表头删(SeqListPopFront)
    • 9.顺序表查找(SeqListFind)
    • 10.在pos位置前插入元素(SeqListInsert)
    • 11.删除pos位置的值(SeqListErase)
  • 三、代码实现
  • 总结


一、顺序表

顺序表是用一段物理结构连续的存储单元依次存储数据元素的线性结构,一般采用数组存储。
顺序表一般分为两种:

  • 静态顺序表:使用定长数组实现
  • 动态顺数表:使用动态开辟的数组实现

本篇文章,顺序表是使用动态开辟的数组实现(动态顺序表)。要实现的功能如下:

//初始化顺序表
void SeqListInit(SeqList* ps);

//销毁顺序表
void SeqListDestroty(SeqList* ps);

//打印顺序表
void SeqListPrint(SeqList* ps);

//顺序表尾插
void SeqListPushBack(SeqList* ps, SLDateType x);

//顺序表头插
void SeqLsitPushFront(SeqList* ps, SLDateType x);

//顺序表尾删
void SeqListPopBack(SeqList* ps);

//顺序表头删
void SeqListPopFront(SeqList* ps);

//顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);

//在pos位置前插入元素
void SeqListInsert(SeqList* ps, int pos, SLDateType x);

//删除pos位置的值
void SeqListErase(SeqList* ps, int pos);

//检查容量
void SeqListCheckCapacity(SeqList* ps);

二、实现思路

画图理解起来更佳!!!

1.存储结构

我们重命名int类型为SLDataType,方便以后我们修改顺序表存储元素的类型。
指针data指向动态开辟的空间,变量sz记录有效的数据元素,变量capacity记录动态开辟空间的大小。

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* data;
	int sz;
	int capacity;
}SeqList;

2.初始化顺序表(SeqListInit)

动态开辟一块空间,用data指针保存空间首地址。
此时data指向空间中有效元素为0,使sz == 0,变量capacity在等于此时开辟空间的大小。

#define SIZE 4

void SeqListInit(SeqList* ps)
{
	ps->data = (SLDataType*)malloc(sizeof(SLDataType) * SIZE);
	if (ps->data == NULL)
	{
		perror("malloc");
		exit(-1);
	}

	ps->sz = 0;
	ps->capacity = SIZE;
}

3.销毁顺序表(SeqListDestroty)

free所开辟的空间,使data == NULL,此时数据有效元素为0,空间大小为0,那么sz = 0,capacity = 0;

//销毁顺序表
void SeqListDestroty(SeqList* ps)
{
	assert(ps);

	//free(ps);
	free(ps->data);
	ps->data = NULL;
	ps->sz = 0;
	ps->capacity = 0;
}

4.打印顺序表(SeqListPrint)

这个函数非常简单,只要遍历一遍所开辟的空间即可,注意范围是(0,sz)。

//打印顺序表
void SeqListPrint(SeqList* ps)
{
	assert(ps);

	for (int i = 0; i < ps->sz; i++)
	{
		printf("%d ", ps->data[i]);
	}
	printf("\n");

}

5.顺序表尾插(SeqListPushBack)and检查容量(SeqListCheckCapacity)

每次加入数据时,我们要先检查空间大小是否充足,再加入数据

  • 检查容量
    在尾插数据前,要检查空间大小是否充足(sz == capacity),如果空间大小不够,要扩大空间大小,capacity记录新的空间大小。

  • 尾插元素
    变量sz不仅代表空间有效元素个数,也代表了新数据元素将要放入的位置。所以尾插元素,只要空间大小充足,那么在data[sz]处放入数据即可,不要忘记sz要加一。

//检查容量
void SeqListCheckCapacity(SeqList* ps)
{
	SLDataType* tmp = (SLDataType*)realloc(ps->data, sizeof(SLDataType) * ps->capacity * 2);
	if (tmp == NULL)
	{
		perror("realloc");
		exit(-1);
	}

	ps->data = tmp;
	ps->capacity *= 2;
}



//顺序表尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{
	assert(ps);

	if (ps->sz == ps->capacity)
	{
		SeqListCheckCapacity(ps);
	}

	ps->data[ps->sz] = x;
	ps->sz++;
}

6.顺序表头插(SeqLsitPushFront)

顺序表除了尾插,尾删不用挪到数据,其它的增删都要挪到数据。
头插数据,要先检查空间大小,再向后挪到数据,将数据放入data[0]处,sz在加一。

//顺序表头插
void SeqLsitPushFront(SeqList* ps, SLDataType x)
{
	assert(ps);

	if (ps->sz == ps->capacity)
	{
		SeqListCheckCapacity(ps);
	}

	int end = ps->sz;
	while (end > 0)
	{
		ps->data[end] = ps->data[end - 1];
		end--;
	}

	ps->data[0] = x;
	ps->sz++;
}

7.顺序表尾删(SeqListPopBack)

变量sz代表有效数据的个数,那么只要sz减一,就代表最后一个数据被删除了。

//顺序表尾删
void SeqListPopBack(SeqList* ps)
{
	assert(ps);
	assert(ps->sz != 0);

	ps->sz--;
}

8.顺序表头删(SeqListPopFront)

头删数据,要将数据从后向前挪到,覆盖掉第一个数据,sz要减一。

//顺序表头删
void SeqListPopFront(SeqList* ps)
{
	assert(ps);
	assert(ps->sz != 0);

	for (int i = 0; i < ps->sz - 1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;
}

9.顺序表查找(SeqListFind)

遍历一遍动态开辟的数组,如果找到了就放回下标,没有就放回-1。

//顺序表查找
int SeqListFind(SeqList* ps, SLDataType x)
{
	assert(ps);

	for (int i = 0; i < ps->sz; i++)
	{
		if (ps->data[i] == x)
		{
			return i;
		}
	}

	return -1;
}

10.在pos位置前插入元素(SeqListInsert)

要先检查空间容量是否充足和要插入的位置是否合法(要在顺序表的有效数据内),再将pos下标后的数据向后挪到,将数据放入data[pos]处,sz加一。
这个函数思路简单,但要注意下面两点:

  • 如果pos == 0,不就是要在顺序表第一个元素前插入元素,不就是顺序表的头插。
  • 如果pos == sz,我们知道sz还表示下一个数据要放入的位置,那么我在下一个数据要放入的位置前插入元素,不就是顺序表的尾插。

理解这点后,我们以后的头插,尾插都可以用该函数复用。方便我们手撕顺序表

//在pos位置前插入元素
void SeqListInsert(SeqList* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->sz);

	if (ps->sz == ps->capacity)
	{
		SeqListCheckCapacity(ps);
	}

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

	ps->data[pos] = x;
	ps->sz++;
}

11.删除pos位置的值(SeqListErase)

删除pos位置处的数据,先检查pos的合法性(要属于[0,sz-1]),要将数据从后向前挪到数据,sz减一。
这个函数思路简单,但要注意下面两点:

  • 如果pos == 0,不就是要删除第一个数据,不就是头删。
  • 如果pos == sz - 1,不就是要删除最后一个数据,不就是尾删。

所以对于尾删,头删函数而言,我们也可以使用该函数复用。

//删除pos位置的值
void SeqListErase(SeqList* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->sz);

	for (int i = pos; i < ps->sz - 1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;
}

三、代码实现

头删,头插,尾删,尾插我都复用了SeqListInsert和SeqListErase。
SeqList.h 文件存放有关函数的声明以及结构体的声明
SeqList.c 文件存放函数的定义

//SeqList.h 文件

#pragma once

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

#define SIZE 4

typedef int SLDataType;

typedef struct SeqList
{
	SLDataType* data;
	int sz;
	int capacity;
}SeqList;



//初始化顺序表
void SeqListInit(SeqList* ps);

//销毁顺序表
void SeqListDestroty(SeqList* ps);

//打印顺序表
void SeqListPrint(SeqList* ps);

//顺序表尾插
void SeqListPushBack(SeqList* ps, SLDateType x);

//顺序表头插
void SeqLsitPushFront(SeqList* ps, SLDateType x);

//顺序表尾删
void SeqListPopBack(SeqList* ps);

//顺序表头删
void SeqListPopFront(SeqList* ps);

//顺序表查找
int SeqListFind(SeqList* ps, SLDateType x);

//在pos位置前插入元素
void SeqListInsert(SeqList* ps, int pos, SLDateType x);

//删除pos位置的值
void SeqListErase(SeqList* ps, int pos);

//检查容量
void SeqListCheckCapacity(SeqList* ps);
//SeqList.c 文件

#include "SeqList.h"


//初始化顺序表
void SeqListInit(SeqList* ps)
{
	ps->data = (SLDataType*)malloc(sizeof(SLDataType) * SIZE);
	if (ps->data == NULL)
	{
		perror("malloc");
		exit(-1);
	}

	ps->sz = 0;
	ps->capacity = SIZE;
}

//检查容量
void SeqListCheckCapacity(SeqList* ps)
{
	SLDataType* tmp = (SLDataType*)realloc(ps->data, sizeof(SLDataType) * ps->capacity * 2);
	if (tmp == NULL)
	{
		perror("realloc");
		exit(-1);
	}

	ps->data = tmp;
	ps->capacity *= 2;
}



//顺序表尾插
void SeqListPushBack(SeqList* ps, SLDataType x)
{
	/*assert(ps);

	if (ps->sz == ps->capacity)
	{
		SeqListCheckCapacity(ps);
	}

	ps->data[ps->sz] = x;
	ps->sz++;*/

	SeqListInsert(ps, ps->sz, x);
}


//打印顺序表
void SeqListPrint(SeqList* ps)
{
	assert(ps);

	for (int i = 0; i < ps->sz; i++)
	{
		printf("%d ", ps->data[i]);
	}
	printf("\n");

}


//销毁顺序表
void SeqListDestroty(SeqList* ps)
{
	assert(ps);

	//free(ps);
	free(ps->data);
	ps->data = NULL;
	ps->sz = 0;
	ps->capacity = 0;
}


//顺序表头插
void SeqLsitPushFront(SeqList* ps, SLDataType x)
{
	/*assert(ps);

	if (ps->sz == ps->capacity)
	{
		SeqListCheckCapacity(ps);
	}

	int end = ps->sz;
	while (end > 0)
	{
		ps->data[end] = ps->data[end - 1];
		end--;
	}

	ps->data[0] = x;
	ps->sz++;*/

	SeqListInsert(ps, 0, x);
}


//顺序表尾删
void SeqListPopBack(SeqList* ps)
{
	/*assert(ps);
	assert(ps->sz != 0);

	ps->sz--;*/

	SeqListErase(ps, ps->sz - 1);
}

//顺序表头删
void SeqListPopFront(SeqList* ps)
{
	/*assert(ps);
	assert(ps->sz != 0);

	for (int i = 0; i < ps->sz - 1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;*/

	SeqListErase(ps, 0);
}


//顺序表查找
int SeqListFind(SeqList* ps, SLDataType x)
{
	assert(ps);

	for (int i = 0; i < ps->sz; i++)
	{
		if (ps->data[i] == x)
		{
			return i;
		}
	}

	return -1;
}


//在pos位置前插入元素
void SeqListInsert(SeqList* ps, int pos, SLDataType x)
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->sz);

	if (ps->sz == ps->capacity)
	{
		SeqListCheckCapacity(ps);
	}

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

	ps->data[pos] = x;
	ps->sz++;
}


//删除pos位置的值
void SeqListErase(SeqList* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->sz);

	for (int i = pos; i < ps->sz - 1; i++)
	{
		ps->data[i] = ps->data[i + 1];
	}
	ps->sz--;
}

总结

以上就是顺序表的实现。谢谢支持!!!

在这里插入图片描述

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

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

相关文章

大数据面试题之Elasticsearch:每日三题(六)

大数据面试题之Elasticsearch:每日三题 1. 为什么要使用Elasticsearch&#xff1f;2.Elasticsearch的master选举流程&#xff1f;3.Elasticsearch集群脑裂问题&#xff1f; 1. 为什么要使用Elasticsearch&#xff1f; 系统中的数据&#xff0c;随着业务的发展&#xff0c;时间…

如何创建一个容器并运行docker镜像

文章目录 如何创建一个容器并使用docker镜像docker命令解析nacos启动成功 访问 进入容器&#xff0c;修改配置文件 接上集 CentOS 7安装Docker https://blog.csdn.net/qq_39017153/article/details/131955100 如何创建一个容器并使用docker镜像 还是打开镜像容器官网https://hu…

JS如何获取最近一个月或指定天数的日期,并以数组的形式存储

JS如何获取最近一个月或指定天数的日期,并以数组的形式存储 代码 num为传递的天数 (传递30查最近一个月) get_date(num) {let dateArray []//获取今天日期let myDate new Date()let today myDate.getFullYear() - (myDate.getMonth() 1) "-" myDate.getDate(…

升讯威在线客服系统是如何实现对 IE8 完全完美支持的(怎样从 WebSocket 降级到 Http)【干货】

简介 升讯威在线客服与营销系统是基于 .net core / WPF 开发的一款在线客服软件&#xff0c;宗旨是&#xff1a; 开放、开源、共享。努力打造 .net 社区的一款优秀开源产品。 完整私有化包下载地址 &#x1f4be; https://kf.shengxunwei.com/freesite.zip 当前版本信息 发布…

【unity之IMGUI实践】敌方逻辑封装实现【六】

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;uni…

技术实力加速企业上云,联想混合云获评专有云优秀案例入选混合云全景图四大方向

7月25-26日&#xff0c;由中国信息通信研究院、中国通信标准化协会联合主办的第十届可信云大会在京顺利召开。大会重磅发布了云计算白皮书&#xff08;2023年&#xff09;、《混合云产业全景图&#xff08;2023&#xff09;》、中国算力服务研究报告、中国云计算发展指数报告等…

Stream流之distinct去重详细用法

前言 distinct方法在Stream流中可以进行集合中的去重操作&#xff0c;但是要按照集合中的数据类型具体来定义。简单数据类型和自定义数据类型操作不同。 简单数据类型 这里以List集合为例&#xff0c;并且集合中数据类型为Integer。简单数据类型直接调用Stream中的distinct方…

抖音短视频seo源码矩阵系统开发

一、前言&#xff1a; 抖音SEO源码矩阵系统开发是一项专为抖音平台设计的SEO优化系统&#xff0c;能够帮助用户提升抖音视频的搜索排名和曝光度。为了确保系统运行正常&#xff0c;需要安装FFmpeg和FFprobe工具。FFmpeg是一个用于处理多媒体数据的开源工具集&#xff0c;而FFpr…

【密码学】三、分组密码的工作模式

分组密码的工作模式 ECB模式CBC模式CFB模式OFB模式CTR模式 电子密码本ECB、密码分组链接模式CBC、密码反馈模式CFB和输出反馈模式OFB、计数器模式CTR ECB模式 它一次对一个64bit长的明文分组加密&#xff0c;而且每次的加密密钥都相同。可以认为有一个非常大的电子密码本&…

在数字化时代,数字孪生能挽回中医的地位嘛?

中医作为中国传统医学的瑰宝&#xff0c;拥有悠久的历史和深厚的文化底蕴。然而&#xff0c;随着现代医学的快速发展&#xff0c;中医面临着许多挑战和困境。在这个数字化时代&#xff0c;数字孪生作为一项前沿技术&#xff0c;是否能为中医行业带来新的希望和机遇呢&#xff1…

制定机器学习规划路线:从入门到专业

文章目录 &#x1f340;第一阶段&#xff1a;入门基础&#x1f340;了解机器学习概念&#x1f340;学习编程和数学基础&#x1f340;探索经典机器学习算法&#x1f340;完成实践项目 &#x1f340;第二阶段&#xff1a;深入学习&#x1f340; 掌握深度学习基础&#x1f340;学习…

无法定位程序输入点:于动态链接库KERNEL32.dll上(未解决)

错误如图&#xff1a; 搜索了一下&#xff0c;说是下载KERNEL32.dll。我在WINDOWS目录下搜索了&#xff0c;实际上这个文件已经存在&#xff1a; 原因猜测&#xff0c;应该是软件本身与系统版本不配套导致的。可能是.NET&#xff1f;C

JAVA课程期末复习学习总结

JAVA课程学习总结 知识点总结 文章目录 JAVA课程学习总结知识点总结Eclipse如何与GitHub连接1.前期准备2.远程建库3.本地操作 常用DOS命令数组正则表达式继承多态向上转型向下转型多态的应用抽象方法 抽象类与接口的异同点不同点&#xff1a;相同点&#xff1a;从设计理念层面…

【MySQL】事务与隔离级别详解

【MySQL】事务 事务的概念为什么要有事务引擎对事务的支持事务的提交方式事务的操作准备正常事务操作&#xff1a;启动、回滚、提交非正常事务总结 事务的隔离级别隔离性隔离级别隔离级别的查看设置隔离级别会话级别全局级别 隔离级别的具体体现读未提交 Read Uncommitted读提交…

本土机器视觉创业企业涌现,深眸科技携手AI+3D视觉勇闯小场景赛道

随着工业自动化技术向智能化方向发展&#xff0c;人工智能实现快速落地&#xff0c;机器视觉应用产品在算力、算法和技术等方面得到持续升级&#xff0c;助力中国机器视觉行业进入高质量发展阶段。 在制造业转型升级、新兴产业发展的过程中&#xff0c;中国作为全球制造中心之…

第十四章:通过迭代挖掘共同物体特征的弱监督语义分割

0.摘要 在图像标签监督下进行弱监督语义分割是一项具有挑战性的任务&#xff0c;因为它直接将高层语义与低层外观相关联。为了弥合这一差距&#xff0c;本文提出了一种迭代的自底向上和自顶向下的框架&#xff0c;交替扩展对象区域和优化分割网络。我们从分类网络产生的初始定位…

新版mmpose训练新版RTMDet/Pose及自定义数据集制作

自定义数据集制作:要求满足目标检测网络和关键点检测网络都可以用其来训练 1. 打开Labelme并导入我们的图像文件夹;2. 用矩形框框出目标检测网络要检测的目标,我们起名叫person;3. 用Creat Point 标记关键点,这里我们只检测人的头和裆两个点。这里教一个小技巧:每一个数据…

Mindar.JS——实现AR图像追踪插入图片或视频

Mindar.JS使用方式 注意&#xff1a;此篇文章需要启动https才可调用相机权限 图像追踪示例 需要用到两个js库 <script src"./js/aframe.min.js"></script><script src"./js/mindar-image-aframe.prod.js"></script>下面看一下标签…

一款性价比高的知识管理系统应具备的功能

编者按&#xff1a;市面上的知识管理系统有不同的类型&#xff0c;有针对文件管理的&#xff0c;也有针对内容管理的&#xff0c;各有长处&#xff0c;那么一款好用的KMS大概都具备哪些优点呢&#xff1f; 关键词&#xff1a;知识管理系统、免运维/安装、 随着企业对企业隐形知…

PyCharm解决Git冲突

什么时候会出现冲突 当我们从远程的仓库pull下来的时候&#xff0c;如果远程仓库跟本地仓库修改了同一个文件&#xff0c;在pull的过程中就会提示合并冲突&#xff1a; $ git pull remote developremote: Enumerating objects: 27, done.remote: Counting objects: 100% (27/2…