线性表之数组

        数组(Array)是 C/C++ 中最基础和重要的数据结构之一,它提供了一种有效存储和访问固定大小元素集合的方式。关于数组的定义和使用相信大家都已经熟练掌握,本文将着重为大家剖析数组的物理结构和逻辑结构。

1. 数组的物理结构

        数组的物理结构是指数组元素在内存中的实际存储方式。在内存中,数组元素是连续存储的,这意味着相邻元素的地址是连续的,且每个元素占用固定大小的内存空间。

        例如,对于一个整型数组 int numbers[5],如果数组的起始地址为 0x1000,每个整型元素占据4个字节,那么数组中的元素在内存中的存储情况可能如下:

0x1000: numbers[0]
0x1004: numbers[1]
0x1008: numbers[2]
0x100C: numbers[3]
0x1010: numbers[4]

        这样的存储方式保证了对数组元素的快速访问和遍历,因为可以通过计算地址偏移来访问数组中的任意元素。

2. 数组的逻辑结构

2.1 线性表

        数组是一种线性数据结构,它由相同类型的元素组成,并以连续的内存地址存储。所谓的线性表就是由一个或多个元素组成的有序序列。在一个线性表中头部节点只有一个后继节点,尾部节点只有一个前驱节点,头部和尾部中间的节点分别有一个前驱节点,一个后继节点,如下图:

        根据从前到后的顺序,我们就可以将A1记作头结点,A5记作尾节点,A2~A4记作中间节点。拿A3举例,它的前驱节点是A2,后继节点是A4。

        在逻辑上,数组是一个有序集合,每个元素可以通过唯一的下标(索引)来访问。

        例如,数组 int numbers[5] 中的元素可以用 numbers[0]、numbers[1]、numbers[2]、numbers[3] 和 numbers[4] 这些下标来访问。这种抽象方式隐藏了数组元素在内存中的实际存储方式,使程序员只需关注元素的逻辑位置而无需担心其物理存储。

2.2 数组的优缺点

关于数组的使用,它的优缺点总结如下:

优点

  • 通过下标访问数组中的任意元素速度非常快,时间复杂度是 O(1)
  • 末尾位置增加、删除元素速度非常快,时间复杂度是O(1)
  • 访问当前元素前、后相邻位置的元素非常方便

缺点

  • 非末尾位置增加、删除元素需要进行大量的数据移动,时间复杂度为 O(n)
  • 数组扩容的时候资源开销比较大

2.3 动态数组

        在C语言中是没有动态数组的概念的,只有静态数组。想要使用动态数组只能由程序员自己实现,其核心思想有以下几点:

  • 记录下数组的容量和数组中存储的数据的个数
  • 当数组的容量 == 存储的数据个数的时候重新申请一块新内存或者扩容

        与此同时,如果要求这个动态数组可以在不同场景下存储不同类型的数据,我们就需要使用泛型编程,因此可以这样定义这个类:

#include <iostream>
using namespace std;template <typename T>
class Array
{
public:Array(int size = 64);~Array();// 在尾部添加元素void append(T val);// 尾部删除元素void popBack();// 插入元素void insert(int pos, T val);// 删除元素void remove(int pos);// 查询元素-> 返回位置int find(T val);// 得到指定位置的元素的值int value(int pos);// 获取数组元素数量int size();// 打印数据void show();
private:void expand(int size);
private:T* m_arry;           // 数组的起始地址int m_capacity;      // 数组容量int m_count;         // 数组中的元素数量
};

        在编写模板类的时候需要注意一个问题:类的声明和定义要写到同一个文件中,如果分开写到 .h 和 .cpp 中,编译的时候就会出现链接错误。因此在实现上边这个的类的时候可以将代码写到一个 .h 或者 .cpp 文件中。

array.cpp 文件

#include <iostream>
#include <cassert>
using namespace std;template <typename T>
class Array
{
public:Array(int size = 64);~Array();// 在尾部添加元素void append(T val);// 尾部删除元素void popBack();// 插入元素void insert(int pos, T val);// 删除元素void remove(int pos);// 查询元素-> 返回位置int find(T val);// 得到指定位置的元素的值int value(int pos);// 获取数组元素数量int size();// 打印数据void show();private:void expand(int size);private:T* m_arry;           // 数组的起始地址int m_capacity;      // 数组容量int m_count;         // 数组中的元素数量
};template <typename T>
Array<T>::Array(int size) :m_capacity(size),m_count(0),m_arry(new T[size]()) 
{
}template <typename T>
Array<T>::~Array()
{// 释放资源delete[]m_arry;m_arry = nullptr;
}template <typename T>
void Array<T>::append(T val)
{// 满了, 扩容if (m_count == m_capacity){expand(m_capacity * 2);}m_arry[m_count++] = val;
}template <typename T>
void Array<T>::popBack()
{if (m_count == 0){return;}m_count--;  // 把尾部元素变成了无效元素
}template <typename T>
void Array<T>::insert(int pos, T val)
{if (pos < 0 || pos > m_count) {cout << "插入数据失败: 无效的pos位置" << endl;return;}if (m_count == m_capacity){expand(2 * m_capacity);}// 移动元素for (int i = m_count - 1; i >= pos; --i){m_arry[i + 1] = m_arry[i];}m_arry[pos] = val;m_count++;
}template <typename T>
void Array<T>::remove(int pos)
{if (pos < 0 || pos >= m_count)  {return;}int value = m_arry[pos];for (int i = pos + 1; i < m_count; ++i){m_arry[i - 1] = m_arry[i];}m_count--;
}template <typename T>
int Array<T>::find(T val)
{for (int i = 0; i < m_count; ++i){if (m_arry[i] == val){return i;}}return -1;
}template<typename T>
int Array<T>::value(int pos)
{assert(pos >= 0 && pos < m_count);return m_arry[pos];
}template<typename T>
int Array<T>::size()
{return m_count;
}template <typename T>
void Array<T>::show()
{for (int i = 0; i < m_count; ++i){cout << m_arry[i] << " ";cout << (int)m_arry[i] << " ";}cout << endl;
}template <typename T>
void Array<T>::expand(int size)
{// 申请一块新的内存T* ptr = new T[size]();// 旧数据拷贝到新内存memcpy(ptr, m_arry, sizeof(T) * m_capacity);delete[]m_arry;// 数据更新m_arry = ptr;m_capacity = size;
}

        上面的代码是通过append或者insert函数往数组中添加数据的时候,判断了数组中已存储的元素数量,如果数组已满便调用expand函数进行扩容。

  • 使用relloc函数扩容比重新分配内存的方式要简单一些,如果它在其它位置开辟了新的存储空间而不是在尾部扩容,会自动释放旧的内存块。
  • 对数组进行动态扩容之后,要对数组的容量进行更新。
  • 对数组进行动态扩容之后,要更新数组指针指向的起始地址。

        另外,通过阅读上述代码也可以证明在数组的中间位置添加、删除数据都会涉及到元素的大量移动(后移或者前移),操作相率相对较低。

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

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

相关文章

大语言模型-GPT3-Language Models are Few-Shot Learners

一、背景信息&#xff1a; GPT3是于2020 年由OpenAI 发布的预训练语言模型。 GPT3在自然语言处理&#xff08;NLP&#xff09;任务中表现出色&#xff0c;可以生成连贯的文本、回答问题、进行对话等。 GPT3的网络架构继续沿用GPT1、GPT2的是多层Transformer Decoder改的结构。…

MySQL的安装配置以及可视化工具的安装

一、MySQL 的安装配置 1、找到官网 MySQL :: Download MySQL Installer (Archived Versions)https://downloads.mysql.com/archives/installer/ 2、下载 3、安装 接下来只需要一直 next 下去就好 此时我们的MySQL就安装完成了&#xff0c;有些人的电脑在点击完这个finish以后…

Linux内核6.12新特性:panic之后扫码显示故障信息

Linux 内核 6.12 版本即将引入一项有趣的功能——在内核Panic时显示一个可选的二维码。这一功能将允许用户通过扫描二维码直接访问内核Panic信息的日志&#xff0c;从而更容易地诊断问题所在。 这不是 Linux 第一次尝试使用二维码。早在2014年&#xff0c;就有过关于在内核Pani…

HarmonyOS(52) 使用安全控件SaveButton保存图片

SaveButton使用简介 前言SaveButton简介约束与限制 实现点击事件全部源码 参考资料&#xff1a; 前言 在HarmonyOS(50) 截图保存功能实现一文中简单介绍了截图保存功能&#xff0c;本篇博文介绍一个更简单的保存图片控件SaveButton. SaveButton简介 SaveButton允许用户通过点…

EasyCVR中的H.265技术:助力实现大规模高效流畅的视频监控应用

随着视频监控技术的不断发展和用户对视频质量要求的不断提高&#xff0c;高效能、低延迟的视频编码技术成为视频监控系统中的重要支撑。TSINGSEE青犀视频旗下的EasyCVR视频汇聚平台凭借其强大的视频处理能力和对H.265技术的支持&#xff0c;在视频监控系统中展现出显著的应用优…

运用Premiere自学视频剪辑,这些岗位你能胜任!

随着短视频的兴起和火热&#xff0c;短视频后期制作越来越受到人们的重视&#xff0c;甚至衍生出很多岗位的高薪工作。如大家所了解的&#xff0c;Adobe premiere正是一款视频后期剪辑和制作工具&#xff0c;其功能强大&#xff0c;应用也十分广泛&#xff0c;是从事后期工作者…

Mysql常见问题汇总【持续更新】

文章目录 Invalid default value for CREATE_TIME 或则 启动时 sql_mode 报错1130错误码&#xff0c;MySQL不能通过ip连接第一种命令方式图形化界面 mysql给用户授管理员权限mysql 新建用户时&#xff0c;主机名选择区别Mysql常用命令大全 Invalid default value for CREATE_T…

四大消息队列:Kafka、ActiveMQ、RabbitMQ、RocketMQ对比

四大消息队列&#xff1a;Kafka、ActiveMQ、RabbitMQ、RocketMQ对比 1. 社区活跃度2. 持久化消息3. 技术实现4. 高并发性能5. RabbitMQ与Kafka对比 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在软件开发中&#xff0c;消息队列&#xf…

基础算法(1)——双指针

1. 概念 常见的双指针有两种形式&#xff0c;一种是对撞指针&#xff0c;一种是快慢指针 1.1 对撞指针 一般用于顺序结构中&#xff0c;也称为左右指针 对撞指针从两端向中间移动&#xff0c;一个指针从最左端开始&#xff0c;另一个从最右端开始&#xff0c;逐渐往中间逼近…

.net dataexcel winform控件 更新 日志

增加 列宽度调整时动态显示列象素大小 更改列的宽度可以使用 column.Width属性进行修改

【持续更新】Mχ Plaayer Pro 1.86.0安卓知名播放器最新免费高级修改版

Mχ Plaayer Pro MOD 版本免费 APK&#xff0c;专为安卓手机和平板打造。这是一款功能强大的视频播放器&#xff0c;具备先进的硬件加速技术和字幕支持功能。 • 硬件加速 - 新增 HW 解码器帮助更多视频格式实现硬件加速。 • 多核心解码 - Mχ Plaayer 是首款支持多核心解码的…

基于STM32的RFID高速收费系统(论文+源码+实物)

1系统方案设计 本文基于STM32的RFID高速收费系统&#xff0c;其可以实现小车和货车两种车型收费&#xff0c;当车辆超过了规定的重量后&#xff0c;出现声光报警提示&#xff0c;并且启动杆不会抬起&#xff0c;只有当车辆重量低于设置值时&#xff0c;启动杆才会自动抬起&…

【Linux】在 bash shell 环境下,当一命令正在执行时,按下 control-Z 会?

目录 题目分析答案 题目 分析 ctrl-c&#xff1a; 发送 SIGINT 信号给前台进程组中的所有进程。常用于终止正在运行的程序&#xff1b;ctrl-z&#xff1a; 发送 SIGTSTP信号给前台进程组中的所有进程&#xff0c;常用于挂起一个进程&#xff1b;ctrl-d&#xff1a; 不是发送信…

揭秘排行榜系统:如何在高并发场景下实现高效更新!

大家好,我是你们的技术分享伙伴小米!今天我们来聊聊一个非常有趣的话题——如何设计一个排行榜。在这个互联网时代,无论是游戏、学习平台,还是各种社交应用,排行榜都是用户互动和竞争的核心功能之一。而如何设计一个高效、实时更新的排行榜,是一个充满挑战性的问题。今天…

win11,vscode上用docker环境跑项目

1.首先用dockerfile创建docker镜像 以下是dockerfile文件的内容&#xff1a; FROM pytorch/pytorch:1.11.0-cuda11.3-cudnn8-devel LABEL Service"SparseInstanceActivation"ENV TZEurope/Moscow ENV DETECTRON_TAGv0.6 ARG DEBIAN_FRONTENDnoninteractiveRUN apt-…

vim常用快捷键问答

vim的光标位置操作快捷键有哪些&#xff1f;怎样记忆它们&#xff1f; 在 Vim 中&#xff0c;光标位置的操作快捷键非常重要&#xff0c;可以帮助你更高效地编辑文本。下面是一些常用的光标位置操作快捷键&#xff1a; 基本移动 h&#xff1a;光标左移一个字符j&#xff1a;光…

使用安信可Ai-WB2-12F开启wifi与手机通信TCP-IP(AT指令)

当时在做两个单片机之间无线通信&#xff0c;或者单片机与手机无线通信&#xff0c;就像找一个蓝牙和wifi双模的无线模块&#xff0c;一开始看ESP8684&#xff08;ESP32-C2&#xff09;这个芯片模组是有wifi和蓝牙的&#xff0c;买回来后才发现他不可以在程序运行中更换蓝牙或者…

主流AI绘画工具-StableDiffusion本地部署方法(mac电脑版本)

Stable Diffusion是一款强大的AI生成图像模型&#xff0c;它可以基于文本描述生成高质量的图像。对于想要在本地运行此模型的用户来说&#xff0c;使用Mac电脑部署Stable Diffusion是一个非常吸引人的选择&#xff0c;特别是对于M1或M2芯片的用户。本文将详细介绍如何在Mac上本…

视频化时代,用好AIGC产品赋能企业培训打造增效降本“最佳实践”

根据IBM的数据&#xff0c;85%的中国企业正在加速投资AI领域&#xff0c;其中超过63%的企业已积极采用生成式AI。德勤的调研进一步显示&#xff0c;近80%的全球受访企业高管认为&#xff0c;生成式AI的兴起与发展将在3年内推动组织和行业发生实质性变革&#xff0c;这也就意味着…

探秘DevSecOps黄金管道,安全与效率的完美融合

软件应用的安全性已成为企业和用户关注的焦点&#xff0c;DevSecOps作为一种将安全融入开发和运维全过程的理念和实践&#xff0c;旨在消除传统开发模式中安全被后置处理的弊端。DevSecOps黄金管道&#xff08;Golden Pipeline&#xff09;是实现这一理念的核心框架&#xff0c…