顺序表的实现【数据结构】

news2024/12/29 13:48:24

1.线性表

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

2.顺序表

顺序表

2.1 概念及结构

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

#define MAX 7
typedef int Datatype;//为了适用不同类型的顺序表
typedef struct SeqList
{
	Daratype a[MAX];
	int sz;//有效数据个数
}SL;

静态顺序表

动态顺序表
使用动态开辟的数组存储

typedef int Datatype;//为了适用不同类型的顺序表
typedef struct SeqList
{
	Daratype* a;
	int sz;//有效数据个数
	int capacity;//存储空间大小
}SL;

动态顺序表

3.模拟实现

静态顺序表只适合于确定知道要存储多少数据的场景下。在储存空间不确定的场景下,对于静态顺序表当MAX开大了就会造成浪费,当MAX开小了又不够。所以在实际的场景中基本都是使用动态顺序表,根据需要动态分配空间大小。
下面是模拟实现:

3.1 准备工作

定义一个结构体

typedef int Datatype;//为了适用不同类型的顺序表
typedef struct SeqList
{
	Datatype* a;
	int sz;//有效数据个数
	int capacity;//存储空间大小
}SL;

3.2 顺序表的初始化与销毁

对于顺序表的初始化,我的话会先给顺序表开好3个空间的大小.
注意:一定要传地址。

void InitSeqlist(SL* ps)
{
	ps->a = (Datatype*)malloc(sizeof(Datatype)*3);
	if(ps->a == NULL)//扩容失败,直接退出程序
	{
		perror("InitSeqlist");
		exit(-1);
	}
	ps->sz = 0;
	ps->capacity = 3;
}

销毁
销毁我们直接free就可以了,任何其他值赋0.

void DestorySeqlist(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->sz = 0;
	ps->capacity = 0;	
}

3.3 顺序表的尾插

插入前我们一定要先检查一下ps是不是应该空指针。
检查完ps后,对于数据的插入会存在两种情况:
1.顺序表已满,需要扩容
2.顺序表未,满直接插入
因为后面的头插与在特定位置的数据插入都会用到检查顺序是否已满,满就扩容的功能,那么我们可以封装成应该函数。

void SeqlistCapacity(SL* ps)
{
	if(ps->capacity == ps->sz)//满了
	{
		Datatype* tmp = (Datatype*)realloc(ps->a, sizeof(Datatype) * 2*ps->capacity);
		if(tmp == NULL)//开辟失败
		{
			perror("realloc");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
}



void PushBack(SL* ps,Datatype x)
{
	assert(ps);
	//检查空间是否已满
	SeqlistCapacity(ps);
	ps->a[ps->sz] = x;
	ps->sz+=1;
}

3.4 顺序表的尾删

删除前我们一定要先检查一下ps是不是应该空指针。
同时还要删除该顺序表中的数据也又两种情况:
1.顺序表中的数据已经删完了,无法再删。
2.顺序表中的数据足够删除。直接删

void PopBack(SL* ps)
{
	assert(ps);
	if(ps->sz>0)
	{
		ps->sz-=1;
	}
}

3.5顺序表的打印

直接打印就好了

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

3.6 顺序表的头插

只要是插入数据就需要检查空间是否已满。
然后头插需要移动数据,我们需要把所有的数据都相后移动一位
这样的话,覆盖的顺序就很重要了,如果从前向后覆盖话,有效数据就没了
前

这样的话2就被覆盖了。
后

这样就不会了,还是不明白的话多画图就可以搞懂了。

void PushFront(SL* ps,Datatype x)
{
	assert(ps);
	SeqlistCapacity(ps);
	for(int i = ps->sz;i>=1;--i)
	{
		ps->a[i] = ps->a[i-1];
	}
	ps->a[0] = x;
	ps->sz += 1;
}

3.7 顺序表的头删

只要是删除就需要判断顺序表是否为空。
这个图我就不画了,大家可以画一画从前面开始覆盖和从后面开始覆盖的图。就会豁然开朗的。

void PopFront(SL* ps)
{
	assert(ps);
	assert(ps->sz!=0);
	for(int i = 0;i<ps->sz-1;++i)
	{
		ps->a[i] = ps->a[i+1];
	}
	ps->sz -= 1; 
}

3.8 顺序表查找

遍历顺序表,没找到的话就返回-1

int FindSeqlist(SL* ps,Datatype x)
{
	assert(ps);
	for(int i = 0;i<ps->sz;++i)
	{
		if(ps->a[i] == x)
			return i;
	}
	return -1;//没找到
}

3.9 顺序表在pos位置插入x

就是类似与头插,头插可以理解为在0位置前插入数据。

void InsertSeqlist(SL* ps,int pos,Datatype x)
{
	assert(ps);
	SeqlistCapacity(ps);
	for(int i = ps->sz;i>=pos+1;--i)
	{
		ps->a[i] = ps->a[i-1];
	}
	ps->a[pos] = x;	
	ps->sz+=1;
}

3.10 顺序表删除pos位置的值

类似于头删

void EraseSeqlist(SL* ps,int pos)
{
	assert(ps);
	assert(ps->sz!=0);
	for(int i = pos;i<ps->sz-1;++i)
	{
		ps->a[i] = ps->a[i+1];
	}
	ps->sz -= 1;
}

4.代码整合

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

typedef int Datatype;//为了适用不同类型的顺序表
typedef struct SeqList
{
	Datatype* a;
	int sz;//有效数据个数
	int capacity;//存储空间大小
}SL;


void InitSeqlist(SL* ps);

void DestorySeqlist(SL* ps);

void SeqlistCapacity(SL* ps);

void PopBack(SL* ps);

void PrintSeqlist(SL* ps);

void PushFront(SL* ps, Datatype x);

void PopFront(SL* ps);

int FindSeqlist(SL* ps, Datatype x);

void InsertSeqlist(SL* ps, int pos, Datatype x);

void EraseSeqlist(SL* ps, int pos);

void PushBack(SL* ps, Datatype x);
//seqlist.c
#include "seqlist.h"

void InitSeqlist(SL* ps)
{
	ps->a = (Datatype*)malloc(sizeof(Datatype) * 3);
	if (ps->a == NULL)//扩容失败,直接退出程序
	{
		perror("InitSeqlist");
		exit(-1);
	}
	ps->sz = 0;
	ps->capacity = 3;
}

void DestorySeqlist(SL* ps)
{
	free(ps->a);
	ps->a = NULL;
	ps->sz = 0;
	ps->capacity = 0;
}

void PushBack(SL* ps, Datatype x)
{
	assert(ps);
	//检查空间是否已满
	SeqlistCapacity(ps);
	ps->a[ps->sz] = x;
	ps->sz += 1;
}

void SeqlistCapacity(SL* ps)
{
	if (ps->capacity == ps->sz)//满了
	{
		Datatype* tmp = (Datatype*)realloc(ps->a, sizeof(Datatype) * 2*ps->capacity);
		if (tmp == NULL)//开辟失败
		{
			perror("realloc");
			exit(-1);
		}
		ps->a = tmp;
		ps->capacity *= 2;
	}
}

void PopBack(SL* ps)
{
	assert(ps);
	if (ps->sz > 0)
	{
		ps->sz -= 1;
	}
}


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

void PushFront(SL* ps, Datatype x)
{
	assert(ps);
	SeqlistCapacity(ps);
	for (int i = ps->sz; i >= 1; --i)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[0] = x;
	ps->sz += 1;
}

void PopFront(SL* ps)
{
	assert(ps);
	assert(ps->sz != 0);
	for (int i = 0; i < ps->sz - 1; ++i)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->sz -= 1;
}

int FindSeqlist(SL* ps, Datatype x)
{
	assert(ps);
	for (int i = 0; i < ps->sz; ++i)
	{
		if (ps->a[i] == x)
			return i;
	}
	return -1;//没找到
}

void InsertSeqlist(SL* ps, int pos, Datatype x)
{
	assert(ps);
	SeqlistCapacity(ps);
	for (int i = ps->sz; i >= pos + 1; --i)
	{
		ps->a[i] = ps->a[i - 1];
	}
	ps->a[pos] = x;
	ps->sz += 1;
}

void EraseSeqlist(SL* ps, int pos)
{
	assert(ps);
	assert(ps->sz != 0);
	for (int i = pos; i < ps->sz - 1; ++i)
	{
		ps->a[i] = ps->a[i + 1];
	}
	ps->sz -= 1;
}

//test.c
#include "seqlist.h"

int main()
{
	//测试
	/*SL sl;
	InitSeqlist(&sl);
	PushBack(&sl, 1);
	PushBack(&sl, 2);
	PushBack(&sl, 3);
	PushBack(&sl, 4);
	PushBack(&sl, 5);
	PushBack(&sl, 6);
	PrintSeqlist(&sl);

	PopBack(&sl);
	PopBack(&sl);
	PopBack(&sl);
	PopBack(&sl);
	PrintSeqlist(&sl);
	PopBack(&sl);
	PopBack(&sl);
	PopBack(&sl);
	PrintSeqlist(&sl);

	PushBack(&sl, 1);
	PushBack(&sl, 2);
	PushBack(&sl, 3);
	PushBack(&sl, 4);
	PushBack(&sl, 5);
	PushBack(&sl, 6);
	PushFront(&sl, 100);
	PushFront(&sl, 200);
	PrintSeqlist(&sl);
	InsertSeqlist(&sl, 0, 1000);
	PrintSeqlist(&sl);

	int pos = FindSeqlist(&sl, 100);
	PopFront(&sl);
	PopFront(&sl);
	PopFront(&sl);

	PopFront(&sl);
	PrintSeqlist(&sl);*/

	//printf("%d", pos);
	return 0;
}

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

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

相关文章

医院设置(洛谷)

设有一棵二叉树&#xff0c;如图&#xff1a; 其中&#xff0c;圈中的数字表示结点中居民的人口。圈边上数字表示结点编号&#xff0c;现在要求在某个结点上建立一个医院&#xff0c;使所有居民所走的路程之和为最小&#xff0c;同时约定&#xff0c;相邻接点之间的距离为 11。…

C语言实现 -- 单链表

C语言实现 -- 单链表 1.顺序表经典算法1.1 移除元素1.2 合并两个有序数组 2.顺序表的问题及思考3.链表3.1 链表的概念及结构3.2 单链表的实现 4.链表的分类 讲链表之前&#xff0c;我们先看两个顺序表经典算法。 1.顺序表经典算法 1.1 移除元素 经典算法OJ题1&#xff1a;移除…

在服务器上使用Dockerfile创建springboot项目的镜像和踩坑避雷

1. 准备个文件夹 这是我的路径 /usr/local/springboot/docker-daka/docker_files2. 将jar包上传 springboot项目打包——maven的package 这是整个项目打包的模式&#xff0c;也可以分离依赖、配置和程序进行打包&#xff0c;详情看我这篇文章&#xff1a; springboot依赖 配…

java基础 之 集合与栈的使用(四)

文章目录 Queue栈Stack队列和栈的区别小扩展自己写个简单的队列自己写个简单的栈使用栈来实现个队列使用队列来实现个栈写在最后 前文回顾&#xff1a; 戳这里 → java基础 之 集合与栈的使用&#xff08;一&#xff09; 戳这里 → java基础 之 集合与栈的使用&#xff08;二&a…

windows中node版本的切换(nvm管理工具),解决项目兼容问题 node版本管理、国内npm源镜像切换(保姆级教程,值得收藏)

前言 在工作中&#xff0c;我们可能同时在进行2个或者多个不同的项目开发&#xff0c;每个项目的需求不同&#xff0c;进而不同项目必须依赖不同版本的NodeJS运行环境&#xff0c;这种情况下&#xff0c;对于维护多个版本的node将会是一件非常麻烦的事情&#xff0c;nvm就是为…

【Git】git 从入门到实战系列(二)—— git 介绍以及安装方法 (文末附带视频录制操作步骤)

文章目录 一、前言二、git 是什么三、版本控制系统是什么四、本地 vs 集中式 vs 分布式本地版本控制系统集中式版本控制系统分布式版本控制系统 五、安装 git 一、前言 本系列上一篇文章【Git】git 从入门到实战系列&#xff08;一&#xff09;—— Git 的诞生&#xff0c;Lin…

Linux系统编程 --- 基础IO

形成共识原理&#xff1a; 1、文件 内容 属性 2、文件分为打开的文件和没打开的文件 3、打开的文件&#xff1a;谁打开&#xff1f;进程&#xff01;--- 本质是研究进程和文件的关系&#xff01; 文件被打开&#xff0c;必须先被加载到内存&#xff01; 一个进程可以打开…

PyTorch 训练自定义功能齐全的神经网络模型的详细教程

在前面的文章中&#xff0c;老牛同学介绍了不少大语言模型的部署、推理和微调&#xff0c;也通过大模型演示了我们的日常的工作需求场景。我们通过大语言模型&#xff0c;实实在在的感受到了它强大的功能&#xff0c;同时也从中受益颇多。 今天&#xff0c;老牛同学想和大家一…

【Android Studiio】default activity 原生安卓和uniapp默认启动分析

文章目录 思路&#xff1a; 一、原生安卓二、uniapp 探究方向&#xff1a;找到Default Activity 思路&#xff1a; 在Android开发中&#xff0c;"default activity"这个概念通常指的是应用启动时默认会加载和显示的那个Activity。AndroidManifest.xml文件是Android…

基于Selenium实现操作网页及操作windows桌面应用

Selenium操作Web页面 Why? 通常情况下&#xff0c;网络安全相关领域&#xff0c;更多是偏重于协议和通信。但是&#xff0c;如果协议通信过程被加密或者无法了解其协议构成&#xff0c;是无法直接通过协议进行处理。此时&#xff0c;可以考虑模拟UI操作&#xff0c;进而实现相…

声音和数据之间的调制解调 —— 电报机和电传打字机如何影响计算机的演变

注&#xff1a;机翻&#xff0c;未校对。 The Squeal of Data The through line between the telegraph and the computer is more direct than you might realize. Its influence can be seen in common technologies, like the modem. 电报和计算机之间的直通线比你想象的要…

基于IOT架构的数据采集监控平台!

LP-SCADA数据采集监控平台是蓝鹏测控推出的一款聚焦于工业领域的自动化数据采集监控系统&#xff0c; 助力数字工厂建设的统一监控平台。 为企业提供从下到上的完整的生产信息采集与集成服务&#xff0c;从而为企业综合自动化、工厂数字化及完整的"管控一体化”的解决方案…

LockSupport详解

文章目录 理解可重入锁LockSupport线程等待唤醒机制&#xff08;wait/notify&#xff09; waitNotify限制awaitSignal限制LockSupport重点说明 理解可重入锁 可重入锁的种类&#xff1a; 隐式锁&#xff08;即synchronized关键字使用的锁&#xff09;默认是可重入锁。 同步代…

站在临床数据科学的角度,药物试验归根结底是这两大假设

在临床数据科学的领域中&#xff0c;药物试验的设计和实施是评估药物效果及其安全性的关键环节。药物试验的基础无外乎两大核心假设&#xff1a;有效性与安全性。这两个假设不仅是药物试验的起点&#xff0c;也是整个研究过程中的重要指导原则。 药物试验的核心主旨在于对待测试…

Python高性能计算:进程、线程、协程、并发、并行、同步、异步

这里写目录标题 进程、线程、协程并发、并行同步、异步I/O密集型任务、CPU密集型任务 进程、线程、协程 进程、线程和协程是计算机程序执行的三种不同方式&#xff0c;它们在资源管理、执行模型和调度机制上有显著的区别。以下是对它们的详细解释和比较&#xff1a; 进程&…

一款有趣的工具,锁定鼠标键盘,绿色免安装

这是一款完全免费的程序&#xff0c;可以实现在不锁定屏幕的情况下锁定鼠标键盘&#xff0c;让鼠标键盘无法操作。比较适合防止误碰鼠标键盘&#xff0c;以及离开电脑时不希望别人操作自己的电脑。 ★★★★★锁定鼠标键盘工具&#xff1a;https://pan.quark.cn/s/e5c518a2165…

路由配置修改(五)

一、默认约定式路由 1、umi 会根据 pages 目录自动生成路由配置。 * name umi 的路由配置* description 只支持 path,component,routes,redirect,wrappers,name,icon 的配置* param path path 只支持两种占位符配置&#xff0c;第一种是动态参数 :id 的形式&#xff0c;第二种…

win11 intel新显卡控制面板无自定义分辨率选项解决

问题 下图是现在的intel显卡控制面板&#xff0c;不知道为啥变得很傻瓜式了&#xff0c;连所有显卡控制面板都有的分辨率自定义也被干掉了。 解决方式 其实解决很简单&#xff0c;因为自定义分辨率对显卡玩游戏来说还是很常用的&#xff0c;intel在beta版又加回来了&#x…

样式与特效(2)——新闻列表

1.盒子模型的边距概念 ) Margin-top 上面 Margin-bottom 底部 Margin-right 右边 Margin-left 左边 Margin : 10px &#xff08;上下左右都是10px&#xff09; Margin &#xff1a;10px,20px (上下边距10px 左右20px) CSS里面最重要的属性之一 将页面理解成…

C++ | Leetcode C++题解之第316题去除重复字母

题目&#xff1a; 题解&#xff1a; class Solution { public:string removeDuplicateLetters(string s) {vector<int> vis(26), num(26);for (char ch : s) {num[ch - a];}string stk;for (char ch : s) {if (!vis[ch - a]) {while (!stk.empty() && stk.back(…