【数据结构】1.顺序表

news2024/11/28 19:33:20

「前言」

🌈个人主页: 代码探秘者
🌈C语言专栏:C语言
🌈C++专栏: C++
🌈喜欢的诗句:天行健,君子以自强不息.

pic_8da49713.png

线性表

线性表(List):零个或多个数据元素的有限序列。

线性表的数据集合为{a1,a2,…,an},假设每个元素的类型均为DataType。其中,除第一个元素a1外,每一个元素有且只有一个直接前驱元素,除了最后一个元素an外,每一个元素有且只有一个直接后继元素。数据元素之间的关系是一对一的关系。
pic_0fdcab7c.png
在较复杂的线性表中,一个数据元素可以由若干个数据项组成。在这种情况下,常把数据元素称为记录,含有大量记录的线性表又称为文件

1、顺序表的基本概念

概念:用一组地址连续的存储单元依次存储线性表的数据元素,这种存储结构的线性表称为顺序表。

特点:逻辑上相邻的数据元素,物理次序也是相邻的。

只要确定好了存储线性表的起始位置,线性表中任一数据元素都可以随机存取,所以线性表的顺序存储结构是一种随机存取的储存结构,因为高级语言中的数组类型也是有随机存取的特性,所以通常我们都使用数组来描述数据结构中的顺序储存结构,用动态分配的一维数组表示线性表。

顺序表和数组的区别

◦ 顺序表的底层结构是数组,对数组的封装,实现了常用的增删改查等接口

1.1 静态顺序表

概念:使用定长数组存储元素
静态顺序表缺陷:空间给少了不够用,给多了造成空间浪费

 静态顺序表(这里拿里面存储的整形举例)
 typedef int SLDataType;
 #define N 100
 typedef struct SeqList
 {
     SLDatatype arr[N];
     int size;//size是有效数据的个数
 }SL;
  
 解释一下为什么要把存储的类型变为SLDataType
 这么做是为了方便以后修改 使用 不同 的类型 
 还有把数组存储的数据容量N 便于修改
1.2 动态顺序表

动态顺序表的结构更加灵活, 可以对结构进行 增删查改,所以我们下面的接口都是通过动态顺序表实现的

2、顺序表存储结构
//头文件
#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;//假设当前元素类型int
//顺序表使用动态数组实现
typedef struct
{
	ElemType* elem;	//动态数组

	int length;		//长度:顺序表当前元素个数

	int ListSize;	//容量:最多存储的个数
}SqList;
3、构造一个空的顺序表L
  • 开辟动态数组,以及初始化长度容量
  • 返回顺序表
//初始化
SqList SqList_Init(int Size)
{
	SqList t;

	t.elem = (ElemType*)malloc(Size * sizeof(ElemType));
	t.length = 0;		//当前长度0
	t.ListSize = Size;  //容量
    
	return t;			//返回顺序表
}
int main()
{
	SqList sl;				//创建顺序表
    
	sl = SqList_Init(10);	//开容量为10的顺序表	
	return 0;
}
4、检查容量,扩容
  • 可以使用malloc或者realloc

  • 用三目运算符(如果开始是0,可以赋值给它,当然我们这里避免了这种情况)

  • 扩容两倍

    //扩容
    void SqList_Capacity(SqList* t)
    {
    	//插入数据之前先看空间够不够
    	if (t->length == t->ListSize)
    	{
    		//申请空间
    		//malloc calloc realloc  int arr[100] --->增容realloc
    		//三目表达式
    		int newCapacity = t->ListSize == 0 ? 4 : 2 * t->ListSize;
    		ElemType* tmp = (ElemType*)realloc(t->elem, newCapacity * sizeof(ElemType));//要申请多大的空间
    		if (tmp == NULL)
    		{
    			perror("realloc fail!");
    			exit(1);//直接退出程序,不再继续执行
    		}
    		//空间申请成功(赋值回来就行)
    		t->elem = tmp;
    		t->ListSize = newCapacity;
    	}
    }
    
5、指定位置前插入元素
  • 顺序表:不为空

  • 检查容量:顺序表是否满了,满了就扩容

  • 位置:判断位置是否合法

  • 移动:根据插入位置需要移动元素个数/次数,将指定位置开始所以元素向后移动位置(从后往前移动)

  • 插入和长度:插入元素,元素个数(length)+1

  • 插入注意:

    • 1.插入位置超过顺序表长度,直接插入指定位置
    • 2.移动再插入
  //指定位置前插入	这里得用指针,因为得修改
  void SqList_Push(SqList* t,int index,ElemType elem)
  {
  	//检查容量:顺序表是否满了,满了就扩容
  	SqList_Capacity(t);
  	//位置:判断位置是否合法
  	if (index >= t->ListSize || index < 0)
  	{
  		printf("位置不合法");
  		return;
  	}
  
  	//移动和插入
  	
  	//如果插入位置超过顺序表长度,直接插入指定位置
  	if (index >= t->length)
  	{
  		t->elem[t->length] = elem;		//这里插入在最后一个元素下一个,不给它乱插
  		t->length++;
  		return;
  	}
  	//移动再插入
  	for (int i = t->length; i >index; i--)
  	{
  		//最开始  length=length-1  最后一个元素移动
  		//结束    index+1=index	   刚好index位置空出来
  		t->elem[i] = t->elem[i - 1];
  	}
  	t->elem[index] = elem;
  	t->length++;
  	return;
  }
6、删除
6.1 删除指定位置元素
  • 顺序表:不为空

  • 下标是否合法

  • 下标i+1至length-1(最后一个元素的下标)移动(从前往后移动)

  • 顺序表长度-1

void SqList_Pop1(SqList* t, int index)
{
	//顺序表:不为空
	if (t == NULL)
	{
		printf("顺序表为空");
		return;
	}
	if (index >= t->ListSize || index < 0)
	{
		printf("位置不合法");
		return;
	}
	//
	//
	for (int i=index; i<t->length-1; i++)
	{
		//最开始  index=index+1			覆盖index位置元素
		//结束    length-2=length-1	    刚好
		t->elem[i] = t->elem[i+1];
	}
	t->length--;	//元素个数减1
}
6.2 删除所有指定元素
  • 顺序表:不为空
  • 遍历顺序表,找到要删的,依次覆盖
//删除所有指定元素
void SqList_Pop2(SqList* t, ElemType elem)
{
	//顺序表:不为空
	if (t == NULL)
	{
		printf("顺序表为空");
		return;
	}
	//开始遍历
	int j = 0;
	while (j != t->length)
	{
		//不是要找的元素,下一个
		if (t->elem[j] != elem)
		{
			j++;
			continue;
		}
		//是,从前往后移动覆盖
		// j  =j+1
		// length-2=length-1
		for (int i = j; i < t->length-1; i++)
		{
			t->elem[i] = t->elem[i + 1];
		}
		t->length--;		//个数减1

		j++;
	}
}
7、查找
7.1 查找指定位置的元素
  • 顺序表:不为空
  • 位置合法
  • 返回下标对应元素
//获取顺序表某一位置上的元素
ElemType  Find_Elem1(SqList t, int index)
{
	//顺序表:不为空
	if (t.length==0)
	{
		printf("顺序表为空");
		return -1;
	}
	//位置合法
	if (index >= t.length || index < 0)
	{
		printf("位置不合法");
		return -1;
	}
	return t.elem[index];
}
7.2 查找指定元素的下标
  • 用index记录,遍历顺序表,如果找到,返回下标。
  • 如果有多个,默认返回第一个。
//查找元素
int  Find_Elem2(SqList t, ElemType elem)
{
	//默认没找到
	int index = -1;
	for (int i = 0; i < t.length; i++)
	{
		if (t.elem[i] == elem)
		{
			//记录元素下标
			index = i;
			break;
		}
	}
	//没有找到
	if (index == -1)
	{
		printf("元素不存在,没有找到");
		return -1;
	}
	return index;
}
8、打印
  • 根据顺序表长度遍历整个顺序表
  • 遍历每个元素输出
  • 用length还是ListSize呢?当然是前者啦,看看前面数据结构定义!
//打印
void SqList_Print(SqList t)
{
	//                         这个是一个宏定义,可以观察行号
	printf("[%s %d]打印顺序表:",__FUNCTION__,__LINE__);
	for (int i = 0; i < t.length; i++)
	{
		printf("%d ", t.elem[i]);
	}
	printf("\n");

9、销毁
//销毁
void SqList_Destory(SqList* t)
{
	if (t == NULL)
	{
		printf("顺序表为空,不能销毁");
		return;
	}
	//动态数组不为空
	if (t->elem)
	{
		free(t->elem);
		t->elem = NULL;
		t->ListSize = t->length = 0;
	}
}
10、测试
int main()
{
	SqList sl;
	sl = SqList_Init(5);			//开容量为5的顺序表	
	for (int i = 0; i < 10; i++)	//插入
	{
		SqList_Push(&sl, i, i);	
	}
	SqList_Print(sl);				//打印
	//查找指定下标4的元素
	int ret1 = Find_Elem1(sl, 4);	
	printf("查找指定下标4的元素:%d\n", ret1);

	//查找元素的下标
	int ret2 = Find_Elem2(sl, 3);	
	printf("查找元素3的下标:%d\n", ret2);

	//删除指定下标元素3
	printf("删除指定下标元素3\n");
	printf("删除前:");
	SqList_Print(sl);
	SqList_Pop1(&sl, 3);	
	printf("删除后:");
	SqList_Print(sl);
	
	//删除指定元素8
	printf("删除指定元素8");
	SqList_Push(&sl, 5, 8);			//再插入一个8
	printf("删除前:");
	SqList_Print(sl);
	SqList_Pop2(&sl, 8);			//删除指定元素8
	printf("删除后:");
	SqList_Print(sl);


	SqList_Destory(&sl);			//销毁
	return 0;
}

测试结果:
在这里插入图片描述

11、 小结
11.1 顺序表时间复杂度

从以上代码可以很明显的看出,线性表的顺序存储结果在读、存数据是的时间复杂度是O(1),插入、删除操作的时间复杂度是O(n)。

11.2 顺序表的优缺点

优点:

  • 无须为表中元素之间的逻辑关系而增加额外的存储空间;
  • 可以快速的存取表中任一位置的元素

缺点:

  • 插入和删除操作需要移动大量元素
  • 当线性表长度较大时,难以确定存储空间的容量;造成存储空间的“碎片”。

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

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

相关文章

软考(网工)——数据通信基础

&#x1f550;信道特性 1️⃣概念 通信得目的就是传递信息。通信中产生和发送信息得一端叫信源&#xff0c;接受信息的一段叫信宿&#xff0c;信源和信宿之间的通信线路称为信道。 2️⃣信道带宽 W 模拟信道&#xff1a;Wf2-f1&#xff08;f2 和 f1分别表示&#xff1a;信道…

树的中心——dfs

题目 代码 #include <bits/stdc.h> using namespace std; const int N 1e510, M N*2; int h[N], e[M], ne[M], idx; int n; int ans 2e9; bool st[N]; void add(int a, int b) // 添加一条边a->b {e[idx] b, ne[idx] h[a], h[a] idx ; } int dfs(int u) {int…

芯片记录一下

1、MC34063 电源管理DCDC 输入电压&#xff1a;-0.3~40V 输出电压&#xff1a;Vout1.25*&#xff08;1R2/R1&#xff09; 1.25V~40V

【报错解决】安装scikit-rebate包报错

scikit-rebate ReBATE是一套基于Relief的机器学习特征选择算法 报错信息 解决方案 conda install numpy scipy scikit-learnpip install skrebate依次运行以上两步&#xff0c;即可成功安装&#xff01;

如何实时监测你的光纤资源?

光纤资源作为重要的通信基础设施&#xff0c;实时监测光纤资源的状态是运营管理好光纤资源的重要手段&#xff0c;那常用的监测指标维度与方法有那些呢&#xff1f; 维度1&#xff1a;资源数量 资源数量主是建立资源的基础档案&#xff0c;掌握光缆的型号、路由&#xff1b;光…

健康推荐系统:SpringBoot技术实现

3系统分析 3.1可行性分析 通过对本基于智能推荐的卫生健康系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本基于智能推荐的卫生健康系统采用SSM框架&#…

python 位运算 笔记

起因&#xff0c; 目的: 位运算&#xff0c;令我头疼的地方。算法题里面也是经常见到。 位运算。 按位或&#xff0c;OR, | , 只要有一个为1&#xff0c; 结果就是1&#xff0c;否则为0按位异或&#xff0c;XOR, ^, 2个数不同&#xff0c;结果为1&#xff0c; 否则为0&#…

k8s jenkins 2.421动态创建slave

k8s jenkins 动态创建slave 简述使用jenkins动态slave的优势&#xff1a;制作jenkins-slave从节点jenkins-slave-latest:v1配置jenkins动态slave配置 Pod Template配置容器模板挂载卷 测试 简述 持续构建与发布是我们日常工作中必不可少的一个步骤&#xff0c;目前大多公司都采…

《OpenCV计算机视觉》—— 使用DNN模块实现图片风格迁移

文章目录 OpenCV中的DNN模块一、功能概述二、支持的模型格式三、基本使用方法四、DNN 模块的特点五、常见应用示例 示例&#xff1a;图片风格迁移 OpenCV中的DNN模块 OpenCV中的DNN&#xff08;Deep Neural Network&#xff09;模块是一个功能强大的工具&#xff0c;它允许开发…

python pip安装requirements.txt依赖与国内镜像

python pip安装requirements.txt依赖与国内镜像 如果网络通畅&#xff0c;直接pip安装依赖&#xff1a; pip install -r requirements.txt 如果需要国内的镜像&#xff0c;可以考虑使用阿里的&#xff0c;在后面加上&#xff1a; -i http://mirrors.aliyun.com/pypi/simple --…

Linux--多路转接之epoll

上一篇:Linux–多路转接之select epoll epoll 是 Linux 下多路复用 I/O 接口 select/poll 的增强版本&#xff0c;它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统 CPU 利用率。它是 Linux 下多路复用 API 的一个选择&#xff0c;相比 select 和 poll&#xff0c…

自建 Bitwarden 密码管理器

大佬零度解说的文件修改,与原文不太一样,详细请看&#xff1a;自建 Bitwarden 密码管理器&#xff01;完全免费开源&#xff0c;轻量级&#xff0c;安全又可靠&#xff01;-零度解说 教程&#xff1a;你的密码真的安全吗&#xff1f;Bitwarden 密码管理器&#xff01;一键部署…

【Redis】缓存预热、雪崩、击穿、穿透、过期删除策略、内存淘汰策略

Redis常见问题总结&#xff1a; Redis常见问题总结Redis缓存预热Redis缓存雪崩Redis缓存击穿Redis缓存穿透 Redis 中 key 的过期删除策略数据删除策略 Redis内存淘汰策略一、Redis对过期数据的处理&#xff08;一&#xff09;相关配置&#xff08;二&#xff09;内存淘汰流程&a…

el-table表格里面有一条横线

表格里面 有一条横线&#xff0c; 出现原因&#xff1a;是自定义了表格头.使用了固定列&#xff08;fixed&#xff09;&#xff0c;定宽。就很难受。。。 添加样式文件&#xff1a; <style lang"scss" scoped>::v-deep {.el-table__fixed-right {height: 100%…

植物大战僵尸杂交版之后要出联机版植物大战僵尸?(内测中,可在安卓手机上玩,文末附下载链接)

继植物大战僵尸杂交版之后给大家介绍一个杂交版作者正在酝酿的“植物大战僵尸射击版” 植物大战僵尸射击版介绍 《植物大战僵尸杂交版》的创作者“潜艇伟伟迷”即将推出PVZ改版新作——《植物大战僵尸射击版》。游戏将支持PC、手游和web端&#xff0c;提供单人、双人、三人、…

取证之FTK Imager学习笔记

一、FTK Imager制作镜像详细教程 1、文件-创建磁盘镜像 2、参数详解&#xff1a; 1&#xff09;物理驱动器 整个驱动器&#xff0c;如&#xff1a;识别到的是整块硬盘、U盘等&#xff0c;而不管你分几个分区&#xff1b; 2&#xff09;逻辑驱动器&#xff08;L&#xff09…

数据结构-5.9.树的存储结构

一.树的逻辑结构&#xff1a; 二.双亲表示法(顺序存储)&#xff1a; 1.树中除了根结点外每一颗树中的任意一个结点都只有一个父结点(双亲结点)&#xff1b; 2.结点包括结点数据和指针&#xff1b; 3.上述图片中右边的顺序存储解析&#xff1a;比如A结点左边的0&#xff0c;就…

机器学习:知识蒸馏(Knowledge Distillation,KD)

知识蒸馏&#xff08;Knowledge Distillation&#xff0c;KD&#xff09;作为深度学习领域中的一种模型压缩技术&#xff0c;主要用于将大规模、复杂的神经网络模型&#xff08;即教师模型&#xff09;压缩为较小的、轻量化的模型&#xff08;即学生模型&#xff09;。在实际应…

Java基础 03

⭐输入法的原理&#xff1a;⭐ 1.输入法本质就是输入字符的编码 2. Unicode对应16位编码-->所有字符都是16进制&#xff08;也就是16进制&#xff09; 码点&#xff1a;一套编码表中&#xff0c;单个字符对应的代码串叫做“码点” 3.变量 Java中所有应用的变量都要声明且…

Python面向对象编程:继承和多态③

文章目录 一、继承1.1 什么是继承1.2 定义父类和子类1.3 子类重写父类的方法1.4 多继承 二、多态2.1 什么是多态2.2 多态的实现2.3 抽象类和接口 三、综合详细例子3.1 项目结构3.2 模块代码init.pyshape.pycircle.pyrectangle.py 3.3 主程序代码main.py 3.4 运行结果 四、总结 …