数据结构——线性表(顺序表)

数据结构——线性表(顺序表)

  • 什么是线性表
  • 顺序表
    • 顺序表结构定义
    • 初始化顺序表
    • 插入
      • 表尾插入
      • 扩容
      • 遍历
      • 指定位置插入
      • 头插
    • 删除
      • 指定位置删除
      • 头删尾删
    • 查找和修改

我们今天进入数据结构的学习,今天我们从梦开始的地方:顺序表

什么是线性表

线性表是一种基本且广泛应用的数据结构,其主要特征如下:

  1. 有限序列
    线性表是由零个或多个数据元素构成的一个有限序列。这意味着线性表中的元素是有顺序的,并且这种排列是明确的,即每个元素都有一个确定的位置。
  2. 相同类型
    线性表中的所有数据元素具有相同的数据类型。这确保了元素在计算机内存中占用相同大小的空间,便于管理和操作。
  3. 一对一关系
    在线性表中,除了第一个元素(表头)可能没有前驱外,每个元素都有且仅有一个直接前驱;除了最后一个元素(表尾)可能没有后继外,每个元素也都有且仅有一个直接后继。这种一对一的关系形成了线性表的线性特性,即元素之间呈线性排列,不存在多对多或一对多的关系。
  4. 线性表的长度
    线性表的长度是指其中包含的数据元素的个数,通常用 n 表示。当 n=0 时,称该线性表为空表。对于非空线性表,可以将其表示为 (a1, a2, ..., an),其中 ai 是第 i 个数据元素。
  5. 基本操作
    线性表支持一系列基本操作,包括但不限于:
  • 初始化:创建一个新的线性表,分配必要的内存空间。
  • 插入:在指定位置插入一个新元素,保持线性表的有序性。
  • 删除:从指定位置移除一个元素,调整剩余元素以保持线性表的连续性。
  • 查找:根据特定条件查找线性表中的元素,返回找到的元素或其位置信息。
  • 修改:更改线性表中某个已知位置上的元素值。
  • 遍历:按顺序访问线性表中的每一个元素,通常用于数据处理、计算或输出。
  1. 存储结构
    线性表可以通过不同的存储结构实现,主要分为两种:
  • 顺序表:元素在计算机内存中按照它们在线性表中的逻辑顺序依次连续存放。访问元素可以根据其索引来直接定位,插入和删除操作则可能需要移动后续元素以维持连续性。
  • 链表(如单向链表、双向链表、单向循环链表、双向循环链表):元素在内存中不一定连续存放,每个元素(结点)包含数据部分和一个或多个指针,用于链接前后相邻元素。链表通过指针关系维护元素间的线性关系,插入和删除操作通常只需修改指针,无需移动元素本身。

总结来说,线性表是一种数据元素呈线性排列、具有相同数据类型、支持高效基本操作的有限序列。它是许多复杂数据结构和算法的基础,广泛应用于各种计算机科学与工程问题中。

顺序表

顺序表是线性表的一种具体实现方式,其特点是将线性表中的元素在计算机内存中按照逻辑顺序(即它们在表中的位置顺序)依次、连续地存放。以下是顺序表的主要特点和操作细节:

特点:

  1. 内存连续性
    顺序表中的元素在内存中占据一片连续的存储区域。每个元素按照它们在线性表中的位置依次紧邻存放。这种内存布局使得可以通过元素的索引(位置序号)直接计算出其在内存中的地址。
  2. 随机访问
    由于元素是连续存放的,给定一个元素的索引,可以立即通过简单的数学计算(通常是索引乘以单个元素的大小)得到其在内存中的地址,从而实现对任意元素的快速访问(O(1)时间复杂度)。这是顺序表相较于链式结构的一大优势。
  3. 预分配空间
    创建顺序表时通常需要预先分配一段固定大小的内存空间来存放元素。随着元素的添加,若空间不足,可能需要动态地申请更大的内存区域,并将原有元素复制到新的内存区域中。这一过程称为“扩容”或“动态增长”,它可能导致额外的时间和空间开销。
  4. 插入和删除的效率依赖于位置
    插入新元素或删除现有元素时,如果是在表尾进行操作,由于不需要移动其他元素,效率相对较高。但如果在表中间插入或删除元素,则需要将受影响的后续元素整体向后(插入时)或向前(删除时)移动一位以保持元素的连续性,这会导致操作的时间复杂度为 O(n),其中 n 是表中元素的数量。

基本操作:

  • 初始化:分配一个足够容纳一定数量元素的连续内存区域,并设置初始元素数量为0。
  • 插入
  • 表尾插入:检查当前元素数量是否达到预设的最大容量。如果没有,直接在末尾位置添加新元素,更新元素数量;如果已满,需要先进行扩容。
  • 指定位置插入:首先确认插入位置的有效性(不能超出当前元素数量范围),然后将该位置及之后的所有元素依次向后移动一位,腾出空位后插入新元素,最后更新元素数量。
  • 删除
  • 指定位置删除:确认删除位置的有效性,将要删除元素之后的所有元素依次向前移动一位以填补空缺,然后更新元素数量。
  • 查找
  • 按索引查找:直接通过索引计算出元素在内存中的地址并访问,时间复杂度为 O(1)。
  • 按值查找:需要从头至尾遍历整个顺序表,逐个比较元素值,找到匹配项或查找不到为止,时间复杂度为 O(n)。
  • 修改
  • 给定元素的索引,可以直接通过索引计算出对应内存地址,然后更新该位置的元素值,时间复杂度为 O(1)。
  • 遍历
  • 从表头开始,按照索引顺序逐个访问元素,直至表尾。

顺序表适用于元素数量稳定、需要频繁随机访问且对插入删除操作效率要求不高的场景。其优点在于简单易实现,支持高效的随机访问和尾部插入删除。缺点则是空间利用率可能不高(尤其当表未填满时),且在表中间进行插入删除操作时效率较低。在实际应用中,选择使用顺序表还是链表等其他线性表实现方式,通常取决于具体的应用需求和性能考量。

顺序表结构定义

我们接下来可以按照这些性质来实现顺序表,但是我们要首先要将顺序表的性质描述出来,定义出来:

我们用C语言实现一下:

#pragma once
#include<stdlib.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>//定义顺序表存放的数据类型
typedef int SData;//定义顺序表结构体
typedef struct SList
{//动态数组SData* _data;//最大容量size_t _capacity;//当前数量size_t _size;
}SList;

初始化顺序表

我们有了顺序表的结构,我们现在可以利用这个结构来完成顺序表的初始化:

//初始化顺序表
bool InitSList(SList* list,size_t capacity)
{//开辟空间list->_data = (SData*)malloc(sizeof (capacity) * capacity);if( list->_data == NULL){perror("malloc fail");return false;}//设置当前数量list->_size = 0;return true;
}

我们可以来测试一下:

#include"Sqlist.h"int main()
{SList list;bool flag = InitSList(&list,10);if(flag == true){printf("init success");}else{printf("init fail");}
}

在这里插入图片描述

插入

表尾插入

表尾插入很简单,直接插入:
在这里插入图片描述
在这里插入图片描述

//尾插
bool TailInsert(SList* list,SData data)
{//检查list是否为空assert(list != NULL);list->_data[list->_size++] = data;return true;
}

但是这样有一个问题,如果线性表满了,这时候就不能插入了,要首先扩容

扩容

扩容会用到realloc这个函数,这个函数可以在原来的地址上开辟指定空间:
在这里插入图片描述

//扩容
bool ReverseCpapcity(SList* list)
{assert(list != NULL);if(list->_size == list->_capacity) //此时当前数量等于最大容量时{//两倍扩容SData* tmp = (SData*) realloc(list->_data,sizeof (SData) * 2 * list->_capacity);if(tmp == NULL){perror("realloc fail");return false;}}return true;
}

修改我们的尾插函数:

//尾插
bool TailInsert(SList* list,SData data)
{//检查list是否为空assert(list != NULL);ReverseCpapcity(list);list->_data[list->_size++] = data;return true;
}

遍历

遍历的话我们直接打印就可以了:

//遍历
void PrintList(SList* list)
{for(int i = 0; i < list->_size; i++){printf("%d ",list->_data[i]);}
}

我们可以测试一下:

#include"Sqlist.h"int main()
{SList list;bool flag = InitSList(&list,10);//尾插TailInsert(&list,23);TailInsert(&list,1);TailInsert(&list,12);TailInsert(&list,99);//遍历PrintList(&list);return 0;
}

在这里插入图片描述

指定位置插入

现在我们想指定位置插入:
在这里插入图片描述
我们的从后往前搬运数据:
在这里插入图片描述
在这里插入图片描述在这里插入图片描述依次类推:
在这里插入图片描述
我们利用一个尾指针帮我们搬运数据:
在这里插入图片描述在这里插入图片描述

//在任意位置插入
bool PosInsert(SList* list,size_t pos, SData data)
{assert(list != NULL && pos >= 0);ReverseCpapcity(list);for(int end = list->_size - 1; end >= pos; end--){list->_data[end + 1] = list->_data[end];}list->_data[pos] = data;list->_size++;return true;
}
#include"Sqlist.h"int main()
{SList list;bool flag = InitSList(&list,10);//尾插TailInsert(&list,23);TailInsert(&list,1);TailInsert(&list,12);TailInsert(&list,99);//任意位置插入PosInsert(&list,2,999);//遍历PrintList(&list);return 0;
}

在这里插入图片描述

头插

头插可以复用在任意位置插入的代码:

//头插
bool FrontInsert(SList* list,SData data)
{return PosInsert(list,0,data);
}

但这里注意一下这里:
在这里插入图片描述这里的pos是size_t无符号整型,在头插的时候pos为0,end会减到-1,如果pos的类型是size_t,这里会有一个默认的整型提升int类型的end会被提升成为size_t的类型,这个时候end就会变成正整数,会比pos大

为了解决这个问题,我们可以强转size_t pos为int
在这里插入图片描述

//在任意位置插入
bool PosInsert(SList* list,size_t pos, SData data)
{assert(list != NULL && pos >= 0);ReverseCpapcity(list);for(int end = list->_size;end >= (int)pos; --end){list->_data[end + 1] = list->_data[end];}list->_data[pos] = data;list->_size++;return true;
}
#include"Sqlist.h"int main()
{SList list;bool flag = InitSList(&list,10);//尾插TailInsert(&list,23);TailInsert(&list,1);TailInsert(&list,12);TailInsert(&list,99);//头插FrontInsert(&list,233);//遍历PrintList(&list);return 0;
}

在这里插入图片描述

删除

指定位置删除

//指定位置删除
bool PosErease(SList* list,size_t pos)
{while(pos < list->_size){list->_data[pos] = list->_data[pos + 1];pos++;}list->_size--;return true;
}
#include"Sqlist.h"int main()
{SList list;bool flag = InitSList(&list,10);//尾插TailInsert(&list,23);TailInsert(&list,1);TailInsert(&list,12);TailInsert(&list,99);//头插FrontInsert(&list,233);//遍历PrintList(&list);//指定位置删除PosErease(&list,3);printf("\n");//遍历PrintList(&list);return 0;
}

在这里插入图片描述

头删尾删

老样子我们可以复用:

//FrontErease
bool FrontErease(SList* list)
{return PosErease(list,0);
}//TailErease
bool TailErease(SList* list)
{return PosErease(list,list->_size-1);
}
#include"Sqlist.h"int main()
{SList list;bool flag = InitSList(&list,10);//尾插TailInsert(&list,23);TailInsert(&list,1);TailInsert(&list,12);TailInsert(&list,99);//头插FrontInsert(&list,233);//遍历PrintList(&list);//指定位置删除PosErease(&list,3);printf("\n");//头删FrontErease(&list);PrintList(&list);printf("\n");//尾删TailErease(&list);PrintList(&list);printf("\n");return 0;
}

在这里插入图片描述

查找和修改

查找和修改都非常简单,这里我们来写写:

//找到指定元素
bool FindData(const SList* list,SData data)
{for(int i = 0; i < list->_size; i++){if(list->_data[i] == data){return true;}}return false;
}//修改指定下标元素
bool FixList(SList *list,size_t pos,SData data)
{assert(pos >= 0 && pos <= list->_size);return list->_data[pos] = data;
}
#include"Sqlist.h"int main()
{SList list;bool flag = InitSList(&list,10);//尾插TailInsert(&list,23);TailInsert(&list,1);TailInsert(&list,12);TailInsert(&list,99);//头插FrontInsert(&list,233);//遍历PrintList(&list);//指定位置删除PosErease(&list,3);printf("\n");//头删FrontErease(&list);PrintList(&list);printf("\n");//尾删TailErease(&list);PrintList(&list);printf("\n");//找到指定元素if(FindData(&list,23)){printf("true\n");}else{printf("false\n");}//修改FixList(&list,0,456);PrintList(&list);printf("\n");return 0;
}

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

支付宝支付之SpringBoot整合支付宝入门

支付宝支付 对接流程 申请阿里支付官方企业账号配置应用签约产品获取RSAKey&#xff08;非对称加密&#xff09;必须获得两个加密串&#xff1a;一个公钥&#xff0c;一个密钥SDK功能开发业务对接支付回调支付组件 核心所需的参数 APPID商家私钥支付宝公钥支付回调地址网关…

MDC使用手册精讲

MDC 背景&#xff1a; 线上排查问题时&#xff0c;请求在多个微服务之间进行调用&#xff0c;并发量较大的情况下&#xff0c;想跟踪某一个请求的链路&#xff0c;是需要花费一些时间才能梳理出来&#xff0c;而且还依赖于你的业务字段。而我们需要的是快速定位&#xff0c;快…

Qt 实战(2)搭建开发环境 | 2.1、Windows下安装QT

一、Windows下安装QT 1、QT官网 QT官网&#xff1a;https://download.qt.io/&#xff0c;打开官网地址&#xff0c;如下&#xff1a; 目录结构介绍 目录说明snapshots预览版&#xff0c;最新的开发测试中的 Qt 库和开发工具onlineQt 在线安装源official_releases正式发布版&am…

python将日志写入文件(超详细)

python将日志写入文件(超详细) 1、需求 我们在训练模型的时候&#xff0c;有时候需要将训练日志输出到一个文件中&#xff0c;方便随时查看训练日志。 训练模型时候&#xff0c;训练日志在控制台展示&#xff0c;关闭控制台后日志会消失。这时&#xff0c;我们需要将控制台中…

STM32之HAL开发——CubeMX配置串行Flash文件系统

配置流程 在开始配置FATFS前&#xff0c;需要提前配置好RCC的时钟&#xff0c;以及时钟的频率&#xff0c;另外还要配置好Debug选项&#xff08;选择串行&#xff09; 选项介绍 文件系统适用于SD卡&#xff0c;Disk磁盘等&#xff0c;需要我们将对应的驱动打开才可以使用。 …

STM32H7 QSPI的寄存器和功能介绍

目录 概述 1 认识QSPI 1.1 QSPI介绍 1.2 QUADSPI 主要特性 2 QUADSPI 功能说明 2.1 双闪存模式禁止 2.2 双闪存模式使能 3 QUADSPI 的用法 3.1 间接模式的操作步骤 3.1.1 QUADSPI 间接模式时配置帧模式 3.1.2 写控制寄存器 (QUADSPI_CR) 3.1.3 写通信配置寄存器 (…

西北新作 | 咸阳金域华庭售楼处落成

优积科技再拓新品,在历史悠久的陕西省咸阳市核心区域&#xff0c;成功打造了一座创新模块化设计的售楼处。 咸阳&#xff0c;这座镶嵌于八百里秦川温润腹地的城市&#xff0c;坐拥渭水潺潺南流&#xff0c;峻嶒嵯峨的嵕山巍然北峙&#xff0c;因其南北皆得山水之阳刚之美&…

MATLAB绘制圆锥曲线:抛物线,双曲线,椭圆

MATLAB绘制圆锥曲线:抛物线,双曲线,椭圆 clc;close all;clear all;warning off;%清除变量x linspace(-10, 10, 1000); % 创建一个x值的向量&#xff0c;范围从-10到10&#xff0c;共1000个点 y x.^2; % 计算每个x值对应的y值% 使用plot函数绘制图形 figure; % 创建一个新的图…

springboot2集成东方通tongweb嵌入式版

由于最近项目需要国产化信创改造&#xff0c;引入东方通tongweb 联系东方通厂家 &#xff0c;将依赖导入到maven仓库&#xff0c;并获取嵌入式版license文件修改pom.xml&#xff0c;引入依赖&#xff0c;注意springboot版本&#xff0c;这里以springboot2举例 首先移除springb…

SpringBoot+Vue多模块项目宝塔部署(保姆级教程)

目录 服务器推荐 安装宝塔 进入宝塔 安装软件 安装 nginx ​编辑 安装mysql 安装java 配置数据库 启动模块下加打包插件 修改配置文件 添加java项目 放行端口 前端访问 本篇博文将向各位详细的介绍项目部署到服务器的详细过程&#xff0c;以及我配置过程中遇到的…

向量数据库与图数据库:理解它们的区别

作者&#xff1a;Elastic Platform Team 大数据管理不仅仅是尽可能存储更多的数据。它关乎能够识别有意义的见解、发现隐藏的模式&#xff0c;并做出明智的决策。这种对高级分析的追求一直是数据建模和存储解决方案创新的驱动力&#xff0c;远远超出了传统关系数据库。 这些创…

蓝桥杯第十五届javab组个人总结

javab组 额今天早上打完了得对自己此次比赛做总结&#xff0c;无论是明年还参赛还是研究生蓝桥杯&#xff0c;体验感有点差&#xff0c;第一题其实一开始想手算但怕进位导致不准确还是让代码跑了&#xff0c;但跑第202420242024个数&#xff08;被20和24整除&#xff09;一直把…