数据结构之顺序表的实现(详解!附完整代码)

news2024/11/24 0:32:44

线性表

线性表(linear list)是n个具有相同特性的数据元素的有限序列。 线性表是一种在实际中广泛使用的数据结构
常见的线性表:顺序表、链表、栈、队列、字符串…
线性表在逻辑上是线性结构,也就说是连续的一条直线。但是在物理结构上并不一定是连续的,线性表在物理上存储时,通常以数组和链式结构的形式存储。
顺序表和链表的存储结构如下:
在这里插入图片描述

顺序表的概念及结构

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

静态顺序表

使用定长数组存储元素:
也就是说,已经把数组的长度内定了,用宏定义了数组的长度
在这里插入图片描述

动态顺序表

使用动态开辟的数组存储:
用malloc函数开辟空间,当数组的存储空间不够可以用realloc扩容,在顺序表中我们用的更多的是动态的顺序表
在这里插入图片描述

顺序表的接口实现

这里我们只实现动态的顺序表,静态顺序表只适用于确定知道需要存多少数据的场景。静态顺序表的定长数组导致N定大了,空间开多了浪费,开少了不够用。所以现实中基本都是使用动态顺序表,根据需要动态的分配空间大小,所以下面我们实现动态顺序表

头文件如下:

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

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	int size;
	int capacity;
}SL;

// 对数据的管理:增删查改 
void SeqListInit(SL* ps);
void SeqListDestroy(SL* ps);

void SeqListPrint(SL* ps);
void SeqListPushBack(SL* ps, SLDateType x);
void SeqListPushFront(SL* ps, SLDateType x);
void SeqListPopFront(SL* ps);
void SeqListPopBack(SL* ps);

// 顺序表查找
int SeqListFind(SL* ps, SLDateType x);
// 顺序表在pos位置插入x
void SeqListInsert(SL* ps, int pos, SLDateType x);
// 顺序表删除pos位置的值
void SeqListErase(SL* ps, int pos);
//修改pos位置的值
void SeqListModify(SL* ps, int pos, SLDateType x);

首先为了方便顺序表的灵活运用,我们用typedef来在头文件中定义int为SLDateType,如果下次是字符型的数据,我们只需要在这里将int改为char,后续的代码就不用更改,其次我们定义一个结构体为顺序表

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;//数组,存放数据
	int size;//数组内存放有效数据的元素
	int capacity;//数组能够存储数据的容量
}SL;//将顺序表有typedef简化为SL,方便后面的代码撰写
初始化顺序表

我们在顺序表中创建一个表后,首先要做的就是初始化这个数据结构,在今后的学习中我们更是要养成一个初始化的习惯,不然很容易出现bug,有些编译器甚至会警告
我们在这里将初始化函数取名为SeqListInit,所需参数为结构体的地址
我们首先断言这个顺序表,防止为空,所以我们在头文件中直接写下assert.h
在这里我们要实现的是动态顺序表,所以我们用malloc动态开辟数组a的空间,记住,要判断动态开辟是否为空,不然部分的编译器会有警告
初始化我们直接将数组的size初始化为0,capacity我们初始化为4
这样我们初始化就完成了

void SeqListInit(SL* ps)
{
	assert(ps);
	ps->a = (SLDateType*)malloc(sizeof(SLDateType) * 4);
	if (ps->a == NULL)
	{
		perror("malloc");
		return;
	}
	ps->size = 0;
	ps->capacity = 4;
}
销毁顺序表

在函数完成后我们需要销毁顺序表,避免内存的浪费和野指针的出现,所以我们定义一个销毁顺序表的函数:
首先要做的还是断言
然后将数组的空间free掉,并将其置为空指针(防止出现野指针),最后将size和capacity都置为0,就完成了销毁

void SeqListDestroy(SL* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}
顺序表打印

我们增删查改后需要打印这个顺序表
打印函数和数组一样,不做过多的讲解

void SeqListPrint(SL* ps)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}
顺序表数据的插入

凡是插入数据,咱们都要检查他的容量是否够,所以我们可以先写一个函数检查容量,如果数组已满,就扩容
当size和capacity相等的时候就是容量已满,我们就realloc开辟一个新的空间,大小为原先a数组的两倍,然后再将新的空间capacity给数组a,capacity变成原来的两倍

void CheckCapacity(SL* ps)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		SLDateType* temp = (SLDateType*)realloc(ps->a,ps->capacity*sizeof(SLDateType*) * 2);
		if (temp == NULL)
		{
			perror("realloc");
			return;
		}
		ps->a = temp;
		ps->capacity *= 2;
	}
}

数据的尾插:
尾插很容易,先检查容量
然后将数组的下标为size的位置插入数据x
同时size要++

void SeqListPushBack(SL* ps, SLDateType x)
{
	assert(ps);
	CheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}

头插:
同样的我们首先检查容量,并且要将所有的数据后移一位,再将数据x插入数组下标为0的位置,同时size++
在这里插入图片描述

void SeqListPushFront(SL* ps, SLDateType x)
{
	assert(ps);
	CheckCapacity(ps);
	int end = ps->size - 1;
	while (end>=0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}
顺序表数据的删除

删除的时候一定要记得断言,因为空顺序表就删不了了
头删:
我们将下标为1的元素往前移动,然后size–就可以完成删除了,移动一次,begin++,同时begin是要小于size的,也就是可以等于size-1

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

尾删:
尾删我们直接将size-1下标的位置置为0,然后size–就可以了,当然,首先就得记得断言!

void SeqListPopBack(SL* ps)
{
	assert(ps);
	ps->a[ps->size - 1] = 0;
	ps->size--;
}
顺序表数据的查找

如果在顺序表中查找一个数据的位置,该怎么办呢?
很简单,我们可以遍历这个数组,然后返回下标就可以了,数据可以直接进行下标的访问,这就很舒服了,如果找不到,这里我就然他返回-1,因为-1是不可能为数组的下标的

int SeqListFind(SL* ps, SLDateType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
		return -1;
	}
}
顺序表pos位置的插入

在这里的插入数据,我们首先要将知道pos位置,而且pos位置要是大于等于0,小于等于size的,因为头插就是下标为0的位置,尾插就是下标为size的位置,之前的头插尾插我们可以直接用这个函数
插入数据我们先将pos位置以及后面的元素的值往后面移动,然后再直接将a[pos]赋值为x,
并且也要从最后一个位置开始往前移动,同时size++
在这里插入图片描述

void SeqListInsert(SL* ps, int pos, SLDateType x)
//先移动后插入
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	CheckCapacity(ps);
	int end = ps->size - 1;
	while (pos <= ps->size - 1)
	{
		ps->a[end+1] = ps->a[end];
		end++;
	}
	ps->a[pos] = x;
	ps->size++;
}
顺序表pos位置的删除

pos位置的删除我们可直接将pos+1位置的元素往前面移动,然后size–
在这里插入图片描述

void SeqListErase(SL* ps, int pos)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	int begin = pos + 1;
	while (begin < ps->size - 1 )//这里是<size-1的原因是因为begin=size-2,begin+1就是size-1了
	{
		ps->a[begin] = ps->a[begin + 1];
		begin++;
	}
	ps->size--;
}
顺序表pos位置的修改

修改也很容易,直接下标访问,赋值为x

void SeqListModify(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	ps->a[pos] = x;
}

到这里,顺序表的实习就完成了,完整代码如下:
头文件:

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

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	int size;
	int capacity;
}SL;

// 对数据的管理:增删查改 
void SeqListInit(SL* ps);
void SeqListDestroy(SL* ps);

void SeqListPrint(SL* ps);
void SeqListPushBack(SL* ps, SLDateType x);
void SeqListPushFront(SL* ps, SLDateType x);
void SeqListPopFront(SL* ps);
void SeqListPopBack(SL* ps);

// 顺序表查找
int SeqListFind(SL* ps, SLDateType x);
// 顺序表在pos位置插入x
void SeqListInsert(SL* ps, int pos, SLDateType x);
// 顺序表删除pos位置的值
void SeqListErase(SL* ps, int pos);
//修改pos位置的值
void SeqListModify(SL* ps, int pos, SLDateType x);

函数定义:

void SeqListInit(SL* ps)
{
	assert(ps);
	ps->a = (SLDateType*)malloc(sizeof(SLDateType) * 4);
	if (ps->a == NULL)
	{
		perror("malloc");
		return;
	}
	ps->size = 0;
	ps->capacity = 4;
}
void SeqListDestroy(SL* ps)
{
	assert(ps);
	free(ps->a);
	ps->a = NULL;
	ps->size = 0;
	ps->capacity = 0;
}
void SeqListPrint(SL* ps)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		printf("%d ", ps->a[i]);
	}
	printf("\n");
}

void CheckCapacity(SL* ps)
{
	assert(ps);
	if (ps->size == ps->capacity)
	{
		SLDateType* temp = (SLDateType*)realloc(ps->a,ps->capacity*sizeof(SLDateType*) * 2);
		if (temp == NULL)
		{
			perror("realloc");
			return;
		}
		ps->a = temp;
		ps->capacity *= 2;
	}
}
//尾插
void SeqListPushBack(SL* ps, SLDateType x)
{
	assert(ps);
	CheckCapacity(ps);
	ps->a[ps->size] = x;
	ps->size++;
}
//头插
void SeqListPushFront(SL* ps, SLDateType x)
{
	assert(ps);
	CheckCapacity(ps);
	int end = ps->size - 1;
	while (end>=0)
	{
		ps->a[end + 1] = ps->a[end];
		end--;
	}
	ps->a[0] = x;
	ps->size++;
}
//头删
void SeqListPopFront(SL* ps)
{
	assert(ps);
	int begin = 1;
	while (begin<ps->size)
	{
		ps->a[begin] = ps->a[begin - 1];
		begin++;
	}
	ps->size--;
	//可以用SeqListErase(ps, 0)
}
//尾删
void SeqListPopBack(SL* ps)
{
	assert(ps);
	ps->a[ps->size - 1] = 0;
	ps->size--;
	//可以用SeqListErase(ps,size-1)
}
// 顺序表查找
int SeqListFind(SL* ps, SLDateType x)
{
	assert(ps);
	for (int i = 0; i < ps->size; i++)
	{
		if (ps->a[i] == x)
		{
			return i;
		}
		return -1;
	}
}
// 顺序表在pos位置插入x
void SeqListInsert(SL* ps, int pos, SLDateType x)
//先移动后插入
{
	assert(ps);
	assert(pos >= 0 && pos <= ps->size);
	CheckCapacity(ps);
	int end = ps->size - 1;
	while (pos <= ps->size - 1)
	{
		ps->a[end+1] = ps->a[end];
		end++;
	}
	ps->a[pos] = x;
	ps->size++;
}

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

void SeqListModify(SL* ps, int pos, SLDateType x)
{
	assert(ps);
	assert(pos >= 0 && pos < ps->size);
	ps->a[pos] = x;
}

今天的分享到这里就结束了,谢谢大家的支持!

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

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

相关文章

十五、W5100S/W5500+RP2040树莓派Pico<TFTP Client>

文章目录 1 前言2 简介2 .1 什么是TFTP&#xff1f;2.2 TFTP的优点2.3 TFTP和FTP对比2.4 TFTP应用场景 3 WIZnet以太网芯片4 ARP网络设置示例概述以及使用4.1 流程图4.2 准备工作核心4.3 连接方式4.4 主要代码概述4.5 结果演示 5 注意事项6 相关链接 1 前言 一般来说&#xff0…

金蝶云星空BOS设计器中基础资料字段属性“过滤”设置获取当前界面的基础资料值作为查询条件

文章目录 金蝶云星空BOS设计器中基础资料字段属性“过滤”设置获取当前界面的基础资料值作为查询条件背景说明业务需求格式BOS配置 金蝶云星空BOS设计器中基础资料字段属性“过滤”设置获取当前界面的基础资料值作为查询条件 背景说明 序列号档案是基础资料&#xff0c;资料里…

delphi程序启动时带参数运行的例子

这里有一个坑&#xff0c;就是参数会减少一个 //需要引用这个单元 uses shellapiprocedure TForm1.Button5Click(Sender: TObject); varParams: string; begin //由于第三个参数不会显示&#xff0c;需要额外的多补充一个参数&#xff0c;而且第一个参数会变成程序的运行路径P…

什么是超级托斯卡纳葡萄酒?

超级托斯卡纳葡萄酒通常被认为是在托斯卡纳用国际葡萄品种制成的葡萄酒&#xff0c;如赤霞珠、品丽珠或梅洛&#xff0c;而不是传统的托斯卡纳葡萄桑娇维塞。来自云仓酒庄品牌雷盛红酒分享这些葡萄酒可能包含一些桑娇维塞&#xff0c;但这通常不是混合中的主要葡萄。这些大胆的…

工程车云管家|叉车智能管家安卓主板方案

工程车云管家是一款功能强大的设备管理和调度系统&#xff0c;它可以实时追踪工程车或机械设备的地理位置、视频、行驶轨迹、油位油耗、工作时长和地点、以及运行状况等信息&#xff0c;并将这些数据通过云平台存储、分析&#xff0c;并发送到管理者的手机上。这使得管理者能够…

Windows安装svn命令

1、svn命令下载地址 https://www.visualsvn.com/downloads/; 2、安装svn命令 3、测试svn命令是否安装成功

Java修仙传之神奇的ES2(巧妙的查询及处理)

SDL语句查询 查询的基本语法 GET /indexName/_search {"query": {"查询类型": {"查询条件": "条件值"}} } 根据文档id查询 #查询文档 GET hotel/_doc/36934 查询所有 会弹出该索引库下所有文档// 查询所有 GET /indexName/_searc…

quickapp_快应用_快应用组件

快应用组件 web组件web页面与快应用页面通信网页接收/发送消息网页接收消息 快应用页面接收/发送消息给网页发送消息 通信前提- trustedurl web组件 作用&#xff1a;用于显示在线的 html 页面(可以嵌入三方页面或者某些不太重要的页面) 缺点&#xff1a;打开会比原生慢一点&…

centos的docker镜像下载ffmpeg的方式

ffmpeg是业界比较好用的开源的音频处理工具&#xff0c;当我们在实际业务中使用ffmpeg的时候&#xff0c;直接使用yum安装回提示找不到ffmpeg的包&#xff0c;遇到这种情况&#xff0c;可以通过以下方式来进行安装&#xff08;docker环境&#xff09;。 已经拥有镜像 更新源 …

激光雷达(LiDAR)技术

激光雷达 LiDAR 不久前引发热议的iPhone 12 Pro机型&#xff0c;配备了全新的LiDAR扫描仪&#xff0c;只需点击自带的Measure应用程序&#xff0c;便能立即测量一个人的身高。 在人工智能和自动驾驶领域&#xff0c;神奇的LiDAR又有着怎样的用处&#xff1f;随着汽车巨头们在…

Redis系列-四种部署方式-单机部署+主从模式+哨兵模式【7】

目录 Redis系列-四种部署方式-单机部署主从模式【7】redis-四种部署模式单机模式主从模式数据同步的方式全量数据同步增量数据同步 Redis哨兵模式总结缺点&#xff1a;哨兵模式应用sentinel.conf配置项 REF 个人主页: 【⭐️个人主页】 需要您的【&#x1f496; 点赞关注】支持…

geoserver发布同一字段的多值渲染

Geoserver之同一字段的多值渲染 有时候我们需要对一个shp的某一字段值中的不同值进行区分展示&#xff0c;但是一般的渲染都是按照统一图层展示的&#xff0c;因此为了更好的效果&#xff0c;我们选择使用uDig等工具处理。 文章目录 Geoserver之同一字段的多值渲染前言一共是分…

【HarmonyOS】HarmonyOS Test测试用例中一些断言API的使用

【关键词】 单元测试框架、HarmonyOS Test、assertThrowError、assertFail、assertEqual 【测试代码及测试结果展示】 这里以新建API9工程自动生成的ohosTest来编写单元测试代码。 1、 测试代码&#xff1a; import { describe, it, expect } from ohos/hypium import abil…

本地电脑如何连接使用腾讯云服务器

如何连接使用腾讯云服务器 在自己的电脑上&#xff0c;单击 &#xff0c;在搜索中&#xff0c;输入 mstsc&#xff0c;按 Enter&#xff0c;打开远程桌面连接对话框。如下图所示&#xff1a; 在“计算机”后面&#xff0c;输入 服务器的公网 IP&#xff0c;就是上节大图左侧…

十三、W5100S/W5500+RP2040树莓派Pico<FTP Server>

文章目录 1. 前言2. 相关简介2.1 简述2.2 原理2.3 优点2.4 应用 3. WIZnet以太网芯片4. FTP Server运行测试4.1 程序流程图4.2 测试准备4.3 连接方式4.4 相关代码4.5 测试现象 5. 注意事项6. 相关链接 1. 前言 在当今的信息化时代&#xff0c;互联网已经成为人们生活、工作不可…

7天入门python系列之第二天python 基础语法

第2天主要是学习Python的基础知识 编者打算开一个python 初学主题的系列文章&#xff0c;用于指导想要学习python的同学。关于文章有任何疑问都可以私信作者。对于初学者想在7天内入门Python&#xff0c;这是一个紧凑的学习计划。但并不是不可完成的。第二天开始python 基础知…

查分小程序,教学大作用

数字化时代&#xff0c;技术已经深深的改变了我们的生活和工作方式。当然&#xff0c;教育领域也不例外。如果你是一位老师&#xff0c;你可能会想知道如何利用这些技术工具来提高学生的学习体验和成绩。今天&#xff0c;我们就来聊聊如何用各种代码、Excel等工具&#xff0c;打…

Redis系列-Redis集群模式【8】

目录 Redis系列-Redis集群模式【8】特性Redis的数据分区虚拟槽分区Redis虚拟槽分区的特点客户端如何定位目标节点&#xff1f; 故障转移故障检测故障转移 Redis一致性保证Redis集群的功能限制部署命令REF 个人主页: 【⭐️个人主页】 需要您的【&#x1f496; 点赞关注】支持 &…

LeetCode148.排序链表

看完题目的想法是&#xff0c;直接把所有节点的值都遍历出来放进优先队列里面&#xff0c;然后从头节点遍历一次&#xff0c;每次把优先队列poll()的值赋给节点的val即可&#xff0c;说实话&#xff0c;想完还觉得估计有问题怎么可能这么简单&#xff0c;但是不管了&#xff0c…

怎么调整excel表里面所有单元格中,某个相同字体大小,单元格中其他文字大小不变?

环境: excel 2021 python3.8 问题描述: 怎么调整excel表里面所有单元格里面1这个字体大小,单元格里面其他文字不变? excel表里面。很多单元格都有1,1和文字都是10号字体,现在想把全部1字字体调整为16号其他字大小都不变 解决方案: 一、使用python来实现,经过测…