数据结构——顺序表的基本操作

前言

介绍

 🍃数据结构专区:数据结构

参考

该部分知识参考于《数据结构(C语言版 第2版)》24~28页

补充

此处的顺序表创建是课本中采用了定义方法为SqList Q来创建,并没有使用顺序表指针的方法,具体两个方法的差别我在此处补充一下

说明:顺序表指针L和顺序表Q都可以表示一个顺序表,但前者是通过指针L间接地表示顺序表,其定义方式为SqList* L,后者是直接地表示顺序表,其定义方式为SqList Q。

前者引用length域的方式为L->length,后者引用length的方式是Q.length。

前者开辟空间的方式是L = (SqList*)malloc(sizeof(SqList)),后者开辟空间使用new.

前者释放空间仅仅需要free(L),后者释放空间需要使用delete[]。

🌈每一个清晨,都是世界对你说的最温柔的早安:ૢ(≧▽≦)و✨


目录

前言

1、顺序表的基本概念

2、顺序表的基本操作

2.1 宏定义与结构体

2.2 初始化

2.3 销毁

2.4 判空

2.5 求表长

2.6 按序号查找(取值)

2.7 按值查找

2.8 插入

2.9 删除

2.10 输出顺序表

2.11 整体代码(含测试)

结语


1、顺序表的基本概念

顺序表(又称顺序存储结构的线性表)是一种线性数据结构,用于存储具有相同类型的数据元素。它使用一段地址连续的存储单元依次存储线性表的数据元素。以下是顺序表的基本概念:

  1. 存储结构
    • 顺序表使用一段连续的存储空间(如数组)来存储数据元素。
    • 每个数据元素在存储空间中都有一个唯一的索引(或位置),可以通过索引快速访问数据元素。
  2. 基本操作
    • 初始化:创建一个空的顺序表,并设置其初始容量。
    • 插入:在顺序表的指定位置插入一个数据元素。可能需要移动元素以腾出空间。
    • 删除:从顺序表的指定位置删除一个数据元素。可能需要移动元素以填补空缺。
    • 查找:根据数据元素的值或索引查找数据元素的位置。
    • 遍历:按顺序访问顺序表中的每个数据元素。
  3. 特点
    • 访问速度快:由于数据元素存储在连续的内存块中,可以通过索引直接访问任意位置的数据元素,时间复杂度为O(1)。
    • 插入和删除操作可能较慢:在顺序表中插入或删除数据元素时,可能需要移动其他数据元素,时间复杂度为O(n),其中n是顺序表的长度。
    • 存储密度高:顺序表中的数据元素在内存中是连续存储的,没有额外的指针开销,存储密度较高。

2、顺序表的基本操作

2.1 宏定义与结构体

#include<iostream>
#include <cstdlib>
using namespace std;

//控制最大值
#define MAXSIZE 1000
//声明Status用于记录返回结果
typedef int Status;
#define OK 1
#define ERROR 0
#define OVERFLOW -1

typedef int ElemType;
typedef struct
{
	ElemType *elem;  //存储空间的基地址
	int length;
}SqList;

2.2 初始化 O(1)

//初始化
Status InitList(SqList& L)
{
	//构造一个空的顺序表
	L.elem = new ElemType[MAXSIZE];  //为顺序表分配一个大小为MAXSIZE的数组空间
	if (!L.elem)                     //如果分配失败就退出
	{
		exit(OVERFLOW);
	}
	L.length = 0;
	return OK;
}

2.3 销毁 O(1)

//销毁  
Status DestroyList(SqList& L)
{
	delete[] L.elem;  // 释放elem指向的数组  
	L.elem = NULL;    // 将指针设为NULL,避免野指针,这一步最好是置为nullptr  
	L.length = 0;     // 长度设为0,虽然这一步在销毁时不是必需的,但可以作为一种清理措施  
	return OK;
}

2.4 判空 O(1)

//判空
Status ListEmpty(SqList L)
{
	if (L.length = 0)
	{
		return OK;
	}
	else
	{
		return ERROR;
	}
}

2.5 求表长 O(1)

//求线性表长度
int ListLength(SqList L)
{
	return(L.length);
}

2.6 按序号查找(取值) O(1)

//取值 ~ 按序号查找
//该算法根据指定的位置序号来获取顺序表中第i个位置的元素的值
//将第i个数据返还给e
Status GetElem(SqList L, int i, ElemType& e)
{
	//1.判断i值是否合理,不合理报错
	if (i < 1 || i > L.length)
	{
		return ERROR;
	}
	e = L.elem[i - 1];   //第i-1位置存储第i个数据
	return OK;
}

2.7 按值查找 O(n)

//按值查找
//从第1个元素开始不断比较e,查找成功返回元素的序号i + 1
int LocateElem(SqList L, ElemType e)
{
	for (int i = 0; i < L.length; i++)
	{
		if (L.elem[i] == e)
		{
			return i + 1;
		}
	}
	return 0;  //查找失败返回0
}

2.8 插入 O(n)

//插入
//在表的第i个位置插入一个新的数据元素e
//第i个位置的下标是i - 1
Status ListInsert(SqList& L, int i, ElemType e)
{
	//判断位置是否合理
    //i的合法位置是 1 <= i <= L.length + 1 
	if (i < 1 || i > L.length + 1)
	{
		return ERROR;
	}
	//判断空间是否充足
	if (L.length == MAXSIZE)
	{
		return ERROR;
	}
    //将要插入位置后面的数据依次向后移动
	for (int j = L.length - 1; j >= i - 1; j--)
	{
		L.elem[j + 1] = L.elem[j];
	}
	L.elem[i - 1] = e;
	++L.length;
	return OK;
}

2.9 删除 O(n)

//删除
//将第i个位置的元素删除,即将i+1至第n个元素依次向前移动一位
Status ListDelete(SqList& L, int i)
{
	//判断i位置是否合法
	if (i < 1 || i > L.length)
	{
		return ERROR;
	}
	for (int j = i; j < L.length; j++)
	{
		L.elem[j - 1] = L.elem[j];
	}
	--L.length;
	return OK;
}

2.10 输出顺序表 O(n)

//输出线性表
void DispList(SqList L)
{
	for (int i = 0; i < L.length; i++)
	{
		cout << L.elem[i] << " ";
	}
	cout << endl;
}

2.11 整体代码(含测试)

#include<iostream>
#include <cstdlib>
using namespace std;

//控制最大值
#define MAXSIZE 1000
//声明Status用于记录返回结果
typedef int Status;
#define OK 1
#define ERROR 0
#define OVERFLOW -1

typedef int ElemType;
typedef struct
{
	ElemType *elem;  //存储空间的基地址
	int length;
}SqList;

//初始化
Status InitList(SqList& L)
{
	//构造一个空的顺序表
	L.elem = new ElemType[MAXSIZE];  //为顺序表分配一个大小为MAXSIZE的数组空间
	if (!L.elem)                     //如果分配失败就退出
	{
		exit(OVERFLOW);
	}
	L.length = 0;
	return OK;
}

//销毁  
Status DestroyList(SqList& L)
{
	delete[] L.elem;  // 释放elem指向的数组  
	L.elem = NULL;    // 将指针设为NULL,避免野指针,这一步最好是置为nullptr  
	L.length = 0;     // 长度设为0,虽然这一步在销毁时不是必需的,但可以作为一种清理措施  
	return OK;
}

//判空
Status ListEmpty(SqList L)
{
	if (L.length = 0)
	{
		return OK;
	}
	else
	{
		return ERROR;
	}
}

//求线性表长度
int ListLength(SqList L)
{
	return(L.length);
}

//取值 ~ 按序号查找
//该算法根据指定的位置序号来获取顺序表中第i个位置的元素的值
//将第i个数据返还给e
Status GetElem(SqList L, int i, ElemType& e)
{
	//1.判断i值是否合理,不合理报错
	if (i < 1 || i > L.length)
	{
		return ERROR;
	}
	e = L.elem[i - 1];   //第i-1位置存储第i个数据
	return OK;
}

//按值查找
//从第1个元素开始不断比较e,查找成功返回元素的序号i + 1
int LocateElem(SqList L, ElemType e)
{
	for (int i = 0; i < L.length; i++)
	{
		if (L.elem[i] == e)
		{
			return i + 1;
		}
	}
	return 0;  //查找失败返回0
}


//插入
//在表的第i个位置插入一个新的数据元素e
//第i个位置的下标是i - 1
Status ListInsert(SqList& L, int i, ElemType e)
{
	//判断位置是否合理
    //i的合法位置是 1 <= i <= L.length + 1 
	if (i < 1 || i > L.length + 1)
	{
		return ERROR;
	}
	//判断空间是否充足
	if (L.length == MAXSIZE)
	{
		return ERROR;
	}
    //将要插入位置后面的数据依次向后移动
	for (int j = L.length - 1; j >= i - 1; j--)
	{
		L.elem[j + 1] = L.elem[j];
	}
	L.elem[i - 1] = e;
	++L.length;
	return OK;
}

//删除
//将第i个位置的元素删除,即将i+1至第n个元素依次向前移动一位
Status ListDelete(SqList& L, int i)
{
	//判断i位置是否合法
	if (i < 1 || i > L.length)
	{
		return ERROR;
	}
	for (int j = i; j <= L.length; j++)
	{
		L.elem[j - 1] = L.elem[j];
	}
	--L.length;
	return OK;
}

//输出线性表
void DispList(SqList L)
{
	for (int i = 0; i < L.length; i++)
	{
		cout << L.elem[i] << " ";
	}
	cout << endl;
}

int main() {
    SqList L;
    ElemType e;
    int position;

    cout << "开始测试顺序表操作函数:" << endl;

    // 测试初始化函数
    cout << "\n1. 测试初始化函数 InitList" << endl;
    if (InitList(L) == OK) {
        cout << "顺序表初始化成功" << endl;
    }
    else {
        cout << "顺序表初始化失败" << endl;
        return 1;
    }

    // 测试插入函数
    cout << "\n2. 测试插入函数 ListInsert" << endl;
    for (int i = 1; i <= 5; i++) 
    {
        if (ListInsert(L, i, i * 10) == OK) 
        {
            cout << "成功在位置 " << i << " 插入元素 " << i * 10 << endl;
        }
        else 
        {
            cout << "在位置 " << i << " 插入元素失败" << endl;
        }
    }

    // 测试输出函数
    cout << "\n3. 测试输出函数 DispList" << endl;
    cout << "当前顺序表内容:";
    DispList(L);

    // 测试取值函数
    cout << "\n4. 测试取值函数 GetElem" << endl;
    if (GetElem(L, 3, e) == OK) {
        cout << "第3个元素的值为:" << e << endl;
    }
    else {
        cout << "获取第3个元素失败" << endl;
    }

    // 测试查找函数
    cout << "\n5. 测试查找函数 LocateElem" << endl;
    e = 30;
    position = LocateElem(L, e);
    if (position) {
        cout << "元素 " << e << " 在顺序表中的位置是:" << position << endl;
    }
    else {
        cout << "元素 " << e << " 不在顺序表中" << endl;
    }

    // 测试删除函数
    cout << "\n6. 测试删除函数 ListDelete" << endl;
    if (ListDelete(L, 2) == OK) {
        cout << "成功删除第2个元素" << endl;
        cout << "删除后的顺序表内容:";
        DispList(L);
    }
    else {
        cout << "删除第2个元素失败" << endl;
    }

    // 测试求长度函数
    cout << "\n7. 测试求长度函数 ListLength" << endl;
    cout << "当前顺序表的长度为:" << ListLength(L) << endl;

    // 测试判空函数
    cout << "\n8. 测试判空函数 ListEmpty" << endl;
    if (ListEmpty(L) == OK) {
        cout << "顺序表为空" << endl;
    }
    else {
        cout << "顺序表不为空" << endl;
    }

    // 测试销毁函数
    cout << "\n9. 测试销毁函数 DestroyList" << endl;
    if (DestroyList(L) == OK) {
        cout << "顺序表销毁成功" << endl;
    }
    else {
        cout << "顺序表销毁失败" << endl;
    }

    // 验证销毁后的状态
    cout << "\n10. 验证销毁后的状态" << endl;
    cout << "销毁后顺序表的长度:" << L.length << endl;
    cout << "销毁后顺序表的指针:" << (L.elem == NULL ? "NULL" : "非NULL") << endl;

    cout << "\n所有测试完成" << endl;

    return 0;
}

结语

顺序表的基本操作是后续学习各类型数据结构的基础,希望大家可以认真来研读每一处代码和每一处逻辑,也希望大家都有所进步!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux系列】查询nginx相关的进程

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

推荐IDE中实用AI编程插件,目前无限次使用

插件介绍 一款字节跳动推出的“基于豆包大模型的智能开发工具” 以vscode介绍【pycharm等都可以啊】&#xff0c;这个插件提供智能补全、智能预测、智能问答等能力&#xff0c;节省开发时间 直接在IDE中使用&#xff0c;就不用在网页中来回切换了 感觉还可以&#xff0c;响应速…

欧盟 RED 网络安全法规 EN 18031

目录 1. &#x1f4c2; EN 18031 1.1 背景 1.2 专业术语 1.3 覆盖产品范围 1.4 EN 18031标准主要评估内容&#xff1a; 1.5 EN 18031标准主要评估项目&#xff1a; 1.6 EN 18031 与 ETSI EN 303 645 的主要差异 1.7 RED 网络安全法规解读研讨会 2. &#x1f531; EN 1…

LabVIEW示波器通信及应用

基于LabVIEW平台开发的罗德与施瓦茨示波器通信与应用系统实现了示波器的远程控制及波形数据的实时分析&#xff0c;通过TCP/IP或USB接口与计算机通信&#xff0c;利用VISA技术进行指令传输&#xff0c;从而实现高效的数据采集与处理功能。 项目背景 随着现代电子测试需求的日益…

【解决Docker无剩余存储磁盘空间问题】

【解决Docker无剩余存储磁盘空间问题】 目录 【解决Docker无剩余存储磁盘空间问题】一、问题概述二、问题原因三、解决方案1、方案一&#xff1a;清除Docker磁盘空间2、方案二&#xff1a;更换Docker磁盘存储目录 一、问题概述 执行Docker build -t [镜像名] [源目录] 命令报错…

2.1 HTML5 - Canvas标签

文章目录 引言Canvas标签概述定义实例&#xff1a;创建画布 理解Canvas坐标系概述实例&#xff1a;获取Canvas坐标 获取Canvas环境上下文概述实例&#xff1a;获取Canvas上下文设置渐变色效果 结语 引言 大家好&#xff0c;今天我们要一起探索HTML5中一个非常有趣且强大的特性…

如何将本地 Node.js 服务部署到宝塔面板:完整的部署指南

文章简介&#xff1a; 将本地开发的 Node.js 项目部署到线上服务器是开发者常见的工作流程之一。在这篇文章中&#xff0c;我将详细介绍如何将本地的 Node.js 服务通过宝塔面板&#xff08;BT 面板&#xff09;上线。宝塔面板是一个强大的服务器管理工具&#xff0c;具有简洁的…

基于SSM党务政务服务热线管理系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;部门管理&#xff0c;办事信息管理&#xff0c;信息记录管理&#xff0c;系统管理 前台账号功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;部门&#xff0c;信息…

金融信创基金行业案例:某基金公司AD信创替代方案建设分享

缺失国产域控统一认证&#xff0c;导致业务信创升级受阻 某基金管理公司在办公场景拟建设信创 OA 系统、信创邮件系统以及信创服务器、桌面终端。但原有的 AD 域既无法接管新购的信创资产&#xff0c;亦不符合全栈信创建设要求。因此&#xff0c;该基金单位必须选择一套稳定可…

H-TCP 的效率和公平性

昨晚带安孩楼下玩耍&#xff0c;用手机 desmos 作了一组 response curve 置于双对数坐标系&#xff1a; 长肥管道的优化思路都很类似&#xff0c;cwnd 增长快一点&#xff1a; BIC TCP&#xff1a;二分查找逼近 capacity&#xff1b;CUBIC TCP&#xff1a;上凸曲线逼近 capa…

PHP爬虫:获取商品销量数据的利器

在电子商务的激烈竞争中&#xff0c;掌握商品销量数据是商家洞察市场动态、制定销售策略的关键。通过PHP爬虫技术&#xff0c;我们可以高效地获取这些数据&#xff0c;为商业决策提供支持。 PHP爬虫的优势 PHP作为一种流行的服务器端脚本语言&#xff0c;拥有跨平台运行、丰富…

2025年天津仁爱学院专升本动画化学工程与工艺专业对应专业限制

天津仁爱学院2025年高职升本科招生专业对应范围目录&#xff08;动画化学工程与工艺&#xff09; 专业名称按照教育部发布的《职业教育专业目录(2021年)(更新时间&#xff1a;2024年1月)》为准&#xff0c;按更新前专业名称录取的学生以下表中原专业名称相符可申报&#xff0c…

SpringBoot项目启动报错:命令行太长解决

文章目录 SpringBoot项目启动报错&#xff1a;命令行太长解决1. 第一种方法1. 第二种方法1-1 旧版本Idea1-2 新版本Idea 3. 重新启动SpringBoot项目即可解决 SpringBoot项目启动报错&#xff1a;命令行太长解决 报错信息&#xff1a; 1. 第一种方法 1. 第二种方法 找到项目…

4 -《本地部署开源大模型》在Ubuntu 22.04系统下部署运行ChatGLM3-6B模型

在Ubuntu 22.04系统下部署运行ChatGLM3-6B模型 大模型部署整体来看并不复杂&#xff0c;且官方一般都会提供标准的模型部署流程&#xff0c;但很多人在部署过程中会遇到各种各样的问题&#xff0c;很难成功部署&#xff0c;主要是因为这个过程会涉及非常多依赖库的安装和更新及…

安防综合管理系统EasyCVR视频汇聚平台Linux环境下如何测试UDP端口是否正常开启?

视频汇聚EasyCVR安防监控视频系统采用先进的网络传输技术&#xff0c;支持高清视频的接入和传输&#xff0c;能够满足大规模、高并发的远程监控需求。平台灵活性强&#xff0c;支持国标GB/T 28181协议、部标JT808、GA/T 1400协议、RTMP、RTSP/Onvif协议、海康Ehome、海康SDK、大…

C++ 中的友元(Friend)用法详解

什么是友元&#xff08;Friend&#xff09;&#xff1f;&#x1f46d; 友元 (C) | Microsoft Learn 在C中&#xff0c;友元&#xff08;Friend&#xff09;是一种机制&#xff0c;允许外部函数或类访问某个类的私有&#xff08;private&#xff09;或保护&#xff08;protecte…

【Spring篇】Spring中的Bean管理

&#x1f9f8;安清h&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;【计算机网络】【Mybatis篇】 &#x1f6a6;作者简介&#xff1a;一个有趣爱睡觉的intp&#xff0c;期待和更多人分享自己所学知识的真诚大学生。 目录 &#x1f3af;Spring IOC容器 &#x1f6a…

【火山引擎】 Chat实践 | 大模型调用实践 | python

目录 一 前期工作 二 Doubao-pro-4k_test实践 一 前期工作 1 已在火山方舟控制台在线推理页面创建了推理接入点 ,接入大语言模型并获取接入点 ID。 2 已参考安装与初始化中的步骤完成 SDK 安装和访问凭证配置

Java面向对象编程基础(二)

Java面向对象编程基础二 一、package与import关键字的使用1.说明2.包的作用3.JDK中主要的包4. import5.import关键字的使用 二、封装性1.为什么要封装&#xff1f;2.如何封装?3.作用4.权限修饰符的权限大小5.案例 三、构造器1 构造器的使用说明2 案例: 四、实例变量赋值过程1 …

【优选算法】(第四十四篇)

目录 ⻜地的数量&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 地图中的最⾼点&#xff08;medium&#xff09; 题目解析 讲解算法原理 编写代码 ⻜地的数量&#xff08;medium&#xff09; 题目解析 1.题目链接&#xff1a;. - 力扣&#xff08;Le…