[数据结构初阶]顺序表

news2024/11/26 21:43:00

目录

静态顺序表

动态顺序表

初始化

 销毁

尾插

​编辑 尾删

头插

头删

Insert

erase

 find查找


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

静态顺序表

定义结构体:

#define N 10//方便修改长度
typedef int SLDateType//方便修改类型
typedef struct SeqList//简化代码
{
	SLDateType a[N];
	size_t  size;
}SL;

通常情况下我们需要存储的数据是未知的,所以我们一般使用动态顺序表而非静态顺序表。

动态顺序表

typedef struct SeqList
{
	SLDateType *a;//指向数组首元素
	size_t  size;//实际存储数据
    size_t capacity;//数组容量,满则扩容
}SL;

初始化

void SLInit(SL* s)//初始化,不然可能存在随机值
{
	s->a = nullptr;
	s->capacity = s->size = 0;
}

注意这里要用指针或引用的方式传递形参才能改变原对象的值。 (实参是形参的拷贝)

 销毁

在出了作用域后我们就得进行销毁操作,以免发生内存泄露

void SLDestory(SL* s)//销毁
{
	if (s->a)
	{
		free(s->a);
		s->a = nullptr;
		s->capacity = s->size = 0;
	}
}

尾插

 尾插实现很简单,需要注意扩容这里可以用2倍扩容,因为频繁扩容是有消耗的

在我们使用realloc进行扩容时,如果指针为空,其作用相当于malloc

底下一段话:如果扩容失败,则会返回一个空指针

如果想避免为空所造成的后果,可以用一个中间变量的方式接收其返回值。

void SLPushBack(SL* s, SLDateType x)//尾插
{
	if (s->size == s->capacity)//扩容
	{
		size_t newCapacity = s->capacity == 0? 4: s->capacity * 2;
		SLDateType *tmp =(SLDateType*)realloc(s->a, newCapacity*sizeof(SLDateType));//原地或异地扩
		if (tmp == nullptr)
		{
			perror("reaaloc fail");
			exit(-1);
		}
		s->a = tmp;
		s->capacity = newCapacity;
	}
	s->a[s->size] = x;
	s->size++;
}

 尾删

先问大家一个问题,尾删需要将删除的位置置0吗?

答案肯定不是,我们通过改变size的大小,使其输出前size个数据就行了,而且有新的数据进来它就会被覆盖掉。那仅仅使size减1就行了吗? 

这里我只对size进行--,可以看到没任何问题 

 这里有个很迷惑人的错误,只有当你使用销毁中的free或者对越界的内存进行写操作才可能被检测出来(读基本不会被检查出来)。因为 编译器对越界的检查是一种抽查行为。(这里我用的是无符号整形修饰size所以free时并不会报错。)

我们可以用aseert或直接返回的方式检查

void SLPopBack(SL* s )//尾删
{
	/*if (s->size == 0)
{
return;
}*/
    assert(s);
	assert(s->size>0);
	s->size--;
}

为了避免对空指针解引用的情况出现,我们也可以在之前的函数面前都进行这样的断言:

	assert(s);

头插

因为头插也涉及扩容,我们可以把实现扩容的代码封装成一个函数。

void SLCheckCapacity(SL* s)
{
	assert(s);
	if (s->size == s->capacity)//扩容
	{
		size_t newCapacity = s->capacity == 0 ? 4 : s->capacity * 2;
		SLDateType* tmp = (SLDateType*)realloc(s->a, newCapacity * sizeof(SLDateType));//原地或异地扩
		if (tmp == nullptr)
		{
			perror("reaaloc fail");
			exit(-1);
		}
		s->a = tmp;
		s->capacity = newCapacity;
	}
}

头插挪动数据一定是从后往前挪,不然会导致数据被覆盖   

void SLPushFront(SL* s, SLDateType x)//头插
{
	assert(s);
	SLCheckCapacity(s);
	//挪动
	int end = s->size - 1;
	while (end >=0)
	{
		s->a[end + 1] = s->a[end];
		end--;
	}
	s->a[0] = x;
	s->size++;

}

 尾插的时间复杂度为O(n),头插为O(n^2)。

头删

void SLPopFront(SL* s)//头删
{
	assert(s);//从前往后
	assert(s->size > 0);//防止越界
	int begin = 1;
	while (begin < s->size )
	{
		//s->a[begin] = s->a[begin + 1];
		s->a[begin-1] = s->a[begin];
		begin++;
	}
	s->size--;
}

 注意这里begin的初始点要取1以免发生越界。

Insert

void SLInsert(SL* s, int pos, SLDateType x)
{
	assert(s);
	assert(pos <= s->size && pos >= 0);//可插入范围
	SLCheckCapacity(s);//插入前检查容量
	int end = s->size - 1;
	while (end >= pos)//从后往前
	{
		s->a[end + 1] = s->a[end];
		end--;
	}
	s->a[pos] = x;
	s->size++;
}

注意pos可以为第size个位置,意为尾插

简化头插尾插代码:

void SLPushFront(SL* s, SLDateType x)//头插
{
	SLInsert(s, 0, x);
}
void SLPushBack(SL* s, SLDateType x)//尾插
{
	SLInsert(s, s->size, x);
}

erase

根据实现头删从前往后的逻辑,我们可以这样实现:

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

注意 这里判断pos范围时间接判断了size的范围,所以可以不用判断size,by the way,删除最后一个数据时不同与插入可以在size位置插入,删除最后一个位置是size-1

尾删头删复用:

void SLPopBack(SL* s )//尾删
{
	SLErase(s, s->size - 1);
}
void SLPopFront(SL* s)//头删
{
	SLErase(s, 0);
}

 find查找

对数据增删查改的查就是找到相应数组下标返回

SLDateType SLFind(SL* s, SLDateType x)//查找
{
	assert(s);
	for (int i = 0; i < s->size; i++)
	{
		if (s->a[i] == x)
		{
			return i;
		}
	}
	return -1;//查找失败返回无效下标
}

 打印函数

void SLPrint(SL* s)
{
	assert(s);

	for (int i = 0; i < s->size; ++i)
	{
		printf("%d ", s->a[i]);
	}
	printf("\n");
}

我们也可以指定从某个位置查找,只需添加一个参数即可。比如删除所有含5的元素:

 菜单

这是一个简单的菜单模板,大家可以自己试一下,需要注意的是,在写程序时,通常是边写边调试,用菜单实际不方便调试。

void menu()
{
	printf("***********************************************\n");
	printf("1、尾插数据 2、尾删数据\n");
	printf("3、头插数据 4、头删数据\n");
	printf("5、打印数据 -1、退出\n");
	printf("***********************************************\n");
}
int main()
{
	SL s;
	SLInit(&s);
	int option = 0;
	int n = 0;
	do
	{
		menu();
		printf("请输入您的操作: ");
		scanf("%d", &option);
		switch (option)
		{
		case 1:
			printf("请输入尾插数据,以-1结束>");
			scanf("%d", &n);
			/*while (scanf("%d", &n) != EOF)*/
			while (n != -1)//-1不存入数据
			{
				SLPushBack(&s, n);
			}
			break;
		case 2:
			SLPopBack(&s);
			break;
		case 3:
			//
			break;
		case 4:
			//
			break;
		case 5:
			SLPrint(&s);
			break;
		default: 
			printf("输入错误,请重新输入");
				break;
		}
	} while (option != -1);
	SLDestory(&s);
//SeqList.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#define N 10//方便修改长度
typedef int SLDateType;//方便修改类型
//typedef struct SeqList
//{
//	SLDateType a[N];
//	size_t size;
//}SL;
//动态:按需
typedef struct SeqList//简化代码
{
	SLDateType *a;
	size_t  size;
	size_t capacity;//数组容量,满则扩容
}SL;
void SLInit(SL* s);//初始化
void SLDestory(SL* s);//销毁

void SLPushBack(SL* s, SLDateType x);//尾插
void SLPopBack(SL* s);//尾删
void SLPushFront(SL* s, SLDateType x);//头插
void SLPopFront(SL* s);//头删
void SLCheckCapacity(SL* s);
void SLInsert(SL* s, int pos, SLDateType x);//插入
void  SLErase(SL* s, int pos);//删除
SLDateType SLFind(SL *s,SLDateType x,int pos);//查找
void SLPrint(SL* s);

 




//SeqList.c
#include"SeqList.h"
void SLCheckCapacity(SL* s)
{
	assert(s);
	if (s->size == s->capacity)//扩容
	{
		size_t newCapacity = s->capacity == 0 ? 4 : s->capacity * 2;
		SLDateType* tmp = (SLDateType*)realloc(s->a, newCapacity * sizeof(SLDateType));//原地或异地扩
		if (tmp == nullptr)
		{
			perror("reaaloc fail");
			exit(-1);
		}
		s->a = tmp;
		s->capacity = newCapacity;
	}
}

void SLInit(SL* s)//初始化,不然可能存在随机值
{
	assert(s);
	s->a = nullptr;
	s->capacity = s->size = 0;
}
void SLPushBack(SL* s, SLDateType x)//尾插
{
	SLInsert(s, s->size, x);
	/*assert(s);
	SLCheckCapacity(s);
	s->a[s->size] = x;
	s->size++;*/
}
void SLDestory(SL* s)//销毁
{
	assert(s);
	if (s->a)
	{
		free(s->a);
		s->a = nullptr;
		s->capacity = s->size = 0;
	}
}
void SLPopBack(SL* s )//尾删
{
	SLErase(s, s->size - 1);
	/*if (s->size == 0)
{
return;
}*/
	/*assert(s);
	assert(s->size>0);
	s->size--;*/

}
void SLPushFront(SL* s, SLDateType x)//头插
{
	SLInsert(s, 0, x);
	//assert(s);
	//SLCheckCapacity(s);
	从后往前挪动
	//int end = s->size - 1;
	//while (end >=0)
	//{
	//	s->a[end + 1] = s->a[end];
	//	end--;
	//}
	//s->a[0] = x;
	//s->size++;
	
}
void SLPopFront(SL* s)//头删
{
	SLErase(s, 0);
	//assert(s);//从前往后
	//assert(s->size > 0);//防止越界
	//int begin = 1;
	//while (begin < s->size )
	//{
	//	//s->a[begin] = s->a[begin + 1];
	//	s->a[begin-1] = s->a[begin];
	//	begin++;
	//}
	//s->size--;
}
void SLInsert(SL* s, int pos, SLDateType x)
{
	assert(s);
	assert(pos <= s->size && pos >= 0);//可插入范围
	SLCheckCapacity(s);//插入前检查容量
	int end = s->size - 1;
	while (end >= pos)//从后往前
	{
		s->a[end + 1] = s->a[end];
		end--;
	}
	s->a[pos] = x;
	s->size++;
}
void  SLErase(SL* s, int pos)
{
	assert(s);
	assert(pos < s->size&& pos >= 0);
	//assert(s->size>0);
	int begin = pos + 1;
	while (begin < s->size)
	{
		s->a[begin - 1] = s->a[begin];
		begin++;
	}
	s->size--;
}
SLDateType SLFind(SL* s, SLDateType x,int pos)//查找
{
	assert(s);
	for (int i = 0; i < s->size; i++)
	{
		if (s->a[i] == x)
		{
			return i;
		}
	}
	return -1;
}
void SLPrint(SL* s)
{
	assert(s);

	for (int i = 0; i < s->size; ++i)
	{
		printf("%d ", s->a[i]);
	}
	printf("\n");
}

以上就是我们顺序表的内容了

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

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

相关文章

Talk | 北卡罗来纳州立大学唐圣坤浙江大学张磊: 数据为中心的高效视觉语言学习—动态退出与数据蒸馏

本期为TechBeat人工智能社区第504期线上Talk&#xff01; 北京时间6月8日(周四)20:00&#xff0c;北卡罗来纳州立大学在读博士生—唐圣坤与浙江大学硕士生—张磊的Talk将准时在TechBeat人工智能社区开播&#xff01; 他们与大家分享的主题是: “数据为中心的高效视觉语言学习…

基于jsp+mysql+mybatis的SpringBoot美容院后台管理系统

运行环境: 最好是java jdk 1.8&#xff0c;我在这个平台上运行的。其他版本理论上也可以。 IDE环境&#xff1a; Eclipse,Myeclipse,IDEA或者Spring Tool Suite都可以&#xff0c;如果编译器的版本太低&#xff0c;需要升级下编译器&#xff0c;不要弄太低的版本 tomcat服务器环…

【嵌入式环境下linux内核及驱动学习笔记-(15)linux总线、设备、驱动模型之I2C总线】

目录 1、 I2C总线机制1.1 导入1.2 时序1.3 地址格式 2、华清fs4412上I2C的实现2.1 寄存器2.2 寄存器位具体含义2.3 fs4412上针对具本设备的I2C工作逻辑2.3.1 主机读写工作流程**2.3.1.1 主机发送时序及操作流程2.3.1.2 主机接收的时序及流程 2.3.2 从机读写工作流程 3、LINUX内…

Redis-认识NoSQl和Redis常见的通用命令

1. 认识NoSQL 非关系型数据库 NoSQL是指一类非关系型数据库&#xff0c;它们采用的数据模型不同于传统的关系模型&#xff0c;它通常使用键值对、文档、图形等非传统的数据结构进行数据存储&#xff0c;不遵循预定义的模式和模型。NoSQL数据库通常分布式、高可扩展性&#xff0…

【项目一】GCC(gcc,g++)、静态库、动态库、MakeFile、GDB调试

GCC、静态库 1.2 GCC(1&#xff09;gcc&#xff08;1&#xff09;常用命令&#xff08;2&#xff09; C程序编译过程&#xff08;3&#xff09;GCC工作流程 1.3 GCC(2&#xff09;g1.3静态库的制作1.5静态库的使用1.6动态库的制作1.7动态库加载失败的原因1.8解决动态库加载失败…

秋招必看,Java后端高频面试题1000题、拒绝简单背诵,深入浅出近30个技术栈

Java 面试随着时间的改变而改变。在过去的日子里&#xff0c;当你知道 String 和 StringBuilder 的区别就能让你直接进入第二轮面试&#xff0c;但是现在问题变得越来越高级&#xff0c;面试官问的问题也更深入。 在我初入职场的时候&#xff0c;类似于 Vector 与 Array 的区别…

面试专题:计算机网络常见面试点总结

socket、tcp、udp、http 的认识及区别 socket、tcp、udp、http 的认识及区别​ 一、先来一个讲TCP、UDP和HTTP关系的 1、TCP/IP是个协议组&#xff0c;可分为三个层次&#xff1a;网络层、传输层和应用层。 在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。 在传…

10分钟让你彻底了解Loadrunner性能测试工具

目录 Loadrunner简介 Loadrunner原理 Loadrunner工具组件 1、VUGen&#xff08;虚拟用户生成器&#xff09; 2、Controller&#xff08;控制器&#xff09; 3、Load Generator&#xff08;负载生成器&#xff09; 4、Analysis分析器 性能测试工具&#xff0c;从广义上讲…

Shell脚本攻略:Linux防火墙

目录 一、理论 1.安全技术 2.防火墙 3.通信五元素和四元素 二、实验 1.iptables基本操作 2.扩展匹配 一、理论 1.安全技术 &#xff08;1&#xff09;安全技术 ①入侵检测系统&#xff08;Intrusion Detection Systems&#xff09;&#xff1a;特点是不阻断任何网络访…

游戏外包开发技术难点分析

游戏开发涉及多个领域的技术&#xff0c;因此在开发过程中可能会遇到很多技术难点。今天和大家分享一些常见的游戏开发技术难点&#xff0c;希望对大家开发游戏有一定帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1. 图形渲染…

「料见」vol25.回顾 | PKU-Beaver开源项目团队:一起来聊首个可复现的RLHF基准

为了解决复现RLHF技术和基于RLHF技术的大预言模型的不安全问题&#xff0c;北京大学团队开源了名为PKU-Beaver&#xff08;海狸&#xff09;开源项目。 第25期料见闭门分享会&#xff0c;我“门”非常开心邀请到PKU-Beaver开源项目团队成员——北京大学人工智能研究院助理教授…

欧美同学会第三届“双创”大赛——空天装备产业赛区(浙江诸暨)正式启动,开启报名通道

6月8日&#xff0c;欧美同学会第三届“双创”大赛——空天装备产业赛区&#xff08;浙江诸暨&#xff09;启动仪式暨北京推介会圆满举行。活动由欧美同学会&#xff08;中国留学人员联谊会&#xff09;主办&#xff0c;中共浙江省委统战部支持&#xff0c;浙江省欧美同学会、中…

国内比较火的报表工具测评——Smartbi电子表格软件和Finereport

最近在学习BI软件&#xff0c;因为最近工作中需要开发报表&#xff0c;因此选用了国内市场比较热门的报表工具——Finereport和Spreadsheet进行学习。 BI软件经常会定期发布新的版本&#xff0c;增加新的功能模块&#xff0c;或者对现有功能进行增强&#xff0c;提升运行效率。…

解决pip install -r requirements.txt 超时

解决方案&#xff1a; pip install -r requirements.txt -i http://pypi.douban.com/simple/ --trusted-host pypi.douban.com测试验证

让你的AndroidUI更亮眼:Jetpack Compose中的可视状态

让你的Android UI更亮眼&#xff1a;Jetpack Compose中的可视状态 任何设计系统的重要责任是清晰地表明哪些组件可以与之交互&#xff0c;哪些不行&#xff0c;并让用户知道交互已发生。本博客文章将解释如何监听Jetpack Compose中的用户交互&#xff0c;并创建可重用的视觉指…

关于接口的安全性测试,这几点你必须掌握!

01、接口防刷 1.为什么会有人要刷接口&#xff1f; 牟利&#xff1a;黄牛在 12306 网上抢票再倒卖。 恶意攻击竞争对手&#xff1a;如短信接口被请求一次&#xff0c;会触发几分钱的运营商费用&#xff0c;当量级大了也很可观。 压测&#xff1a;用apache bench 做压力测试。…

高性能计算与AI融合成为刚需|什么是高性能计算?应用领域有哪些?与人工智能的关系梳理

本文一部分转载自杨净 整理自 MEET2023量子位 算力的需求&#xff0c;远比以往来得更为猛烈。甚至有人直呼&#xff1a;得算力者得未来。 元宇宙、AIGC、AI for Science的涌现&#xff0c;又给高性能计算&#xff08;HPC&#xff09;平添了好几把火。 在诸多挑战与机遇共存交…

大数据治理入门系列:数据管理

在如今的大数据时代&#xff0c;每天都会产生大量的新数据&#xff0c;已有数据可能也会频繁更新或转换。因此&#xff0c;需要对数据进行治理和管理&#xff0c;以便高效地开展数据分析、获取数据洞见、挖掘数据价值。否则&#xff0c;杂乱无章的数据只会白白浪费存储空间&…

python基础----10-----python操作mysql

一 前言 对于SQL章节前言->SQL_DQL_排序分页的课程&#xff0c;这里不做记录&#xff0c;因为都是讲MYSQL本身的内容&#xff0c;与python无关。 当然&#xff0c;接下来的课需要用到mysql&#xff0c;所以大家需要自行下载&#xff0c;这并不难。 二 python操作MYSQL基础…

当BPM遇上低代码 “自定义”提升业务管理效率

业务流程管理&#xff08;BPM&#xff09;的历史可以追溯到科学管理和质量管理的发展&#xff0c;并逐步演变为一个更加系统化和综合的管理方法。它在现代组织中起到了优化业务流程、提高效率和质量、增强灵活性和创新能力的重要作用。 从20世纪初的科学管理理论中&#xff0c…