C++ 数据结构 静态顺序表、动态顺序表。
静态顺序表(Static Array List)是一种线性数据结构,通常用数组实现。它具有固定的大小,并在编译时分配内存。以下是静态顺序表的一些基本概念和实现示例。
静态顺序表基本概念
- 固定大小:静态顺序表的大小在创建时定义,无法动态扩展。
- 数组实现:使用数组存储数据元素,支持随机访问。
- 插入和删除操作:需要移动元素以保持顺序,可能会影响性能。
- 顺序存储:元素在内存中是连续存储的,支持高效的随机访问。
1. 数据结构示意图
假设我们有一个静态顺序表的初始状态如下(数组最大容量为5):
Index: 0 1 2 3 4+---+---+---+---+---+
Data: | | | | | |+---+---+---+---+---+
Length: 0
2. 尾部插入
操作:将元素10
插入到表的末尾。
Index: 0 1 2 3 4+---+---+---+---+---+
Data: | 10| | | | |+---+---+---+---+---+
Length: 1
这里因为是一个空表,所以插入之后值就是index是0的位置。
3. 头部插入
操作:将元素5
插入到表的头部(索引0)。
Index: 0 1 2 3 4+---+---+---+---+---+
Data: | 5| 10| | | |+---+---+---+---+---+
Length: 2
4. 中间插入
操作:将元素7
插入到索引1的位置。
过程:
- 移动元素
10
(从索引1到索引2)以为新元素腾出空间。
结果:
Index: 0 1 2 3 4+---+---+---+---+---+
Data: | 5| 7| 10| | |+---+---+---+---+---+
Length: 3
#include <iostream>
#include <stdexcept>
#include <string>const int MAX_SIZE = 5; // 最大容量template <typename T>
class StaticArrayList {
public:StaticArrayList() : m_length(0) {} // 构造函数,初始化长度为0~StaticArrayList() {} // 默认析构函数// 插入元素bool insert(int index, const T &value) {if (index < 0 || index > m_length || m_length >= MAX_SIZE) {return false; // 索引越界或已满}// 移动元素以腾出插入位置for (int i = m_length; i > index; --i) {m_data[i] = m_data[i - 1];}m_data[index] = value; // 插入新元素m_length++;return true;}// 删除元素bool remove(int index) {if (index < 0 || index >= m_length) {return false; // 索引越界}// 移动元素以填补删除位置for (int i = index; i < m_length - 1; ++i) {m_data[i] = m_data[i + 1];}m_length--;return true;}// 获取元素T get(int index) const {if (index < 0 || index >= m_length) {throw std::out_of_range("Index out of range"); // 异常处理}return m_data[index]; // 返回元素}// 获取当前长度int size() const {return m_length; // 返回当前元素个数}// 打印所有元素void print() const {for (int i = 0; i < m_length; ++i) {std::cout << m_data[i] << " "; // 输出元素}std::cout << std::endl; // 换行}private:T m_data[MAX_SIZE]; // 存储元素的数组int m_length; // 当前元素个数
};int main() {StaticArrayList<int> list; list.insert(0, 10);list.insert(1, 20);list.insert(1, 15);list.print(); // 输出: 10 15 20list.remove(1);list.print(); // 输出: 10 20try {std::cout << "Element at index 0: " << list.get(0) << std::endl; }catch (const std::out_of_range &e) {std::cerr << e.what() << std::endl; }return 0;
}
动态顺序表(Dynamic Array List)是一个可以动态调整大小的线性数据结构,通常使用动态分配的数组来实现。与静态顺序表相比,动态顺序表的大小可以根据需要进行扩展和收缩。以下是动态顺序表的基本概念和实现示例。
动态顺序表基本概念
- 动态大小:可以根据元素数量动态调整大小。
- 数组实现:使用动态分配的数组存储数据元素,支持随机访问。
- 插入和删除:在尾部插入操作比较高效,而在中间插入或删除时需要移动元素。
#include <iostream>
#include <stdexcept> // 用于异常处理template <typename T>
class DynamicArrayList {
public:DynamicArrayList() : m_size(0), m_capacity(2) {try {m_data = new T[m_capacity]; // 动态分配数组}catch (const std::bad_alloc &e) {std::cerr << "Memory allocation failed: " << e.what() << std::endl;throw; // 重新抛出异常以便上层处理}}~DynamicArrayList() {delete[] m_data; // 释放动态分配的数组}// 插入元素void insert(const T &value) {if (m_size >= m_capacity) {resize(); // 扩展容量}m_data[m_size++] = value; // 添加新元素}// 删除元素bool remove(int index) {if (index < 0 || index >= m_size) {return false; // 索引越界}for (int i = index; i < m_size - 1; ++i) {m_data[i] = m_data[i + 1]; // 移动元素}m_size--;return true;}// 获取元素T get(int index) const {if (index < 0 || index >= m_size) {throw std::out_of_range("Index out of range"); // 异常处理}return m_data[index]; // 返回元素}// 获取当前长度int size() const {return m_size; // 返回当前元素个数}// 打印所有元素void print() const {for (int i = 0; i < m_size; ++i) {std::cout << m_data[i] << " "; // 输出元素}std::cout << std::endl; // 换行}private:T *m_data; // 动态分配的数组int m_size; // 当前元素个数int m_capacity; // 当前容量// 扩展容量void resize() {m_capacity *= 2; // 容量翻倍T *newData = nullptr;try {newData = new T[m_capacity]; // 创建新数组}catch (const std::bad_alloc &e) {std::cerr << "Memory allocation failed during resize: " << e.what() << std::endl;throw; // 重新抛出异常}for (int i = 0; i < m_size; ++i) {newData[i] = m_data[i]; // 复制元素}delete[] m_data; // 释放旧数组m_data = newData; // 更新指针}
};int main() {try {DynamicArrayList<int> list; // 创建动态顺序表实例list.insert(10);list.insert(20);list.insert(30);list.print(); // 输出: 10 20 30list.remove(1);list.print(); // 输出: 10 30std::cout << "Element at index 0: " << list.get(0) << std::endl; // 输出: 10}catch (const std::bad_alloc &e) {std::cerr << "Failed to allocate memory: " << e.what() << std::endl;}catch (const std::out_of_range &e) {std::cerr << e.what() << std::endl; // 捕获越界异常}return 0;
}
1. 动态数组的优缺点
-
优点:
- 动态调整大小:可以根据需要增加或减少数组的大小,灵活性较高。
- 随机访问:支持O(1)时间复杂度的随机访问。
-
缺点:
- 插入和删除效率:在数组中间插入或删除元素时,需要移动元素,时间复杂度为O(n)。
- 内存分配:每次扩展容量时,需要分配新内存并复制数据,可能会导致性能下降。
2. 扩展策略
- 容量翻倍:在数组满时将容量翻倍是一种常见的扩展策略,能有效减少频繁的内存分配操作。
- 减少容量:可以考虑在删除元素后,如果数组的使用率低于某个阈值(如25%),则缩小数组的容量,以节省内存。
3. 迭代器支持
为了使动态顺序表更加灵活,可以实现迭代器支持,允许用户使用范围for
循环遍历元素。这需要定义一个迭代器类,并在动态数组类中实现相关方法。
4. 拷贝构造和赋值运算符
- 拷贝构造函数:在类中添加拷贝构造函数,以支持深拷贝。
- 赋值运算符重载:实现赋值运算符重载以支持正确的赋值操作,避免浅拷贝引起的问题。
5. 线程安全
在多线程环境中,如果多个线程同时访问动态数组,可能会导致数据不一致或崩溃。可以通过加锁机制或使用原子操作来实现线程安全。
6. 性能优化
- 预分配内存:如果预知元素数量,可以在初始化时分配足够的内存,避免频繁扩展。
- 内存池:使用内存池技术,减少频繁的动态内存分配操作,提高性能。
代码(包含拷贝构造和赋值运算符)
下面是改进后的动态顺序表示例,添加了拷贝构造函数和赋值运算符重载:
#include <iostream>
#include <stdexcept>template <typename T>
class DynamicArrayList {
public:DynamicArrayList() : m_size(0), m_capacity(2) {m_data = new T[m_capacity];}~DynamicArrayList() {delete[] m_data;}// 拷贝构造函数DynamicArrayList(const DynamicArrayList& other) {m_size = other.m_size;m_capacity = other.m_capacity;m_data = new T[m_capacity];for (int i = 0; i < m_size; ++i) {m_data[i] = other.m_data[i];}}// 赋值运算符重载DynamicArrayList& operator=(const DynamicArrayList& other) {if (this != &other) {delete[] m_data; // 释放旧内存m_size = other.m_size;m_capacity = other.m_capacity;m_data = new T[m_capacity]; // 分配新内存for (int i = 0; i < m_size; ++i) {m_data[i] = other.m_data[i];}}return *this;}// 插入、删除、获取等方法保持不变...private:T* m_data;int m_size;int m_capacity;void resize() {// resize 实现...}
};int main() {// 示例操作...return 0;
}
相关文章:
C++ 数据结构 静态顺序表、动态顺序表。
静态顺序表(Static Array List)是一种线性数据结构,通常用数组实现。它具有固定的大小,并在编译时分配内存。以下是静态顺序表的一些基本概念和实现示例。 静态顺序表基本概念 固定大小:静态顺序表的大小在创建时定义…...

QML旋转选择器组件Tumbler
1. 介绍 Tumbler是一个用于创建旋转选择器的组件。它提供了一种直观的方式来让用户从一组选项中进行选择,类似于转盘式数字密码锁。网上找的类似网图如下: 在QML里,这种组件一共有两个版本,分别在QtQuick.Extras 1.4(旧)和QtQuic…...
在工作中常用到的 Linux 命令总结
引言 我之前找工作面试的时候。几乎每次面试几乎都会问到 Linux 常用命令,会问一些命令的应用场景。目的是考察我们是否在实际开发中经常用、用得熟练。今天我就来系统地总结一下开发过程中最常用的 Linux 命令,算是一个复习总结。 基本操作 文件管理…...

反射、枚举和lambda表达式
文章目录 一、反射1.1 什么是反射1.2 反射相关的类1.3 示例获取Class对象通过反射去创建对象调用带两个参数且私有的构造方法获取私有属性反射私有方法 二、枚举2.1 什么是枚举以及其优缺点2.2 如何使用枚举组织常量的基本方法枚举类的其他方法示例枚举能否通过反射拿到实例对象…...

Stable Diffusion Web UI 1.9.4常用插件扩展-WD14-tagger
Stable Diffusion Web UI 1.9.4 运行在 WSL 中的 Docker 容器中 tagger 插件的作用是,上传一张图片,反推这张图片可能的提示词。 使用场景就是,想要得到类似的图片内容时使用。 WD14-tagger 安装 Stable Diffusion WebUI WD14-tagger GitH…...
java 第19天 Lambda、jdk8.0新方法、Optional
一.Lambda表达式 前提是:参数是函数式接口才可以书写Lambda表达式 函数式接口条件: 1.接口 2.只有一个抽象方法 lambda表达式又称为匿名函数,允许匿名函数以参数的形式传入方法,简化代码 lambda表达式分为两部分()->{} …...

江协科技STM32学习- P31 I2C通信协议
🚀write in front🚀 🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🎁欢迎各位→点赞👍 收藏⭐️ 留言📝…...

6、liunx目录的功能
一、目录简介 Linux主要树结构目录包括:/、/root、/home、/usr、/bin、/tmp、/sbin、/proc、/boot 【Linux系统中常见目录功能如下】 / 根目录;/bin 存放必要的命令;(普通用户) /boot 存放内核以及启动所需的文件&…...
挑战Java面试题复习第5天,无人扶我青云志
挑战第 5 天 java反射List Set Map 区别Object 常用方法 java反射 定义: 运行时动态获取类信息和调用方法的特性。 应用场景: JDBC数据库连接。框架如Hibernate和Struts等。 实现方式: 通过四种方法获取Class对象: Class.fo…...

大规模语言模型:从理论到实践(1)
1、绪论 大规模语言模型(Large Language Models,LLM)是由包含数百亿以上参数的深度神经网络构建的语言模型,采用自监督学习方法通过大量无标注文本进行训练。自2018年以来,多个公司和研究机构相继发布了多种模型&#…...
C#如何锁定和解除鼠标及键盘BlockInput
在C#中,"BlockInput"通常指的是一个功能或方法,用于阻止或暂停用户输入一段时间。这在某些特定的应用场景下非常有用,比如在游戏中防止玩家连续快速点击导致游戏逻辑错误,或者在UI应用中防止用户在某个操作正在进行时进…...

Stable Diffusion 3.5发布:图像生成新纪元,多模态AI的突破!
在人工智能的图像生成领域,我们刚刚迎来了一位新的明星——Stable Diffusion 3.5。这是一款由多模态扩散Transformer(MMDiT)驱动的文本到图像模型,它在图像质量、字体处理、复杂提示理解以及资源效率方面都实现了显著提升。今天&a…...

MySQL超大分页怎么优化处理?limit 1000000,10 和 limit 10区别?覆盖索引、面试题
1. limit 100000,10 和 limit 10区别 LIMIT 100000, 10: 这个语句的意思是,从查询结果中跳过前100000条记录,然后返回接下来的10条记录。这通常用于分页查询中,当你需要跳过大量的记录以获取后续的记录时。例如,如果你…...
RabbitMQ 实现消息队列负载均衡
在现代应用程序中,消息队列是一种重要的架构模式,用于解耦服务、处理异步任务和实现负载均衡。其中,RabbitMQ是一个广泛使用的开源消息代理,提供了高可用性、可靠性和灵活性。本文将展示如何使用Python及其pika库来实现RabbitMQ&a…...
嵌入式linux中HTTP协议原理基本分析
第一:HTTP协议简介 超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。 HTTP的发展是由蒂姆伯纳斯-李于1989年在欧洲核子研究组织(CERN)所发起。HTTP的标准制定由万维…...

thinkphp和vue基于Workerman搭建Websocket服务实现用户实时聊天,完整前后端源码demo及数据表sql
最近接了一个陪玩小程序,其中有一个实时聊天的项目,需要搭建Websocke服务,通过多方考虑选择了通过GatewayWorker框架(基于Workerman),将代码提取了出来,用到的框架封装到了vendor目录下,完整前后…...
浅谈射频应用
射频(Radio Frequency,缩写为RF)是一种高频交流变化电磁波的简称,其频率范围广泛,从几十千赫兹跨越至几百吉赫兹。射频技术在多个领域有着广泛的应用: 1、通信领域:射频技术是现代通信领域的重要…...

SAP(PP生产制造)拆解工单业务处理
1、BOM维护 要拆解的成品或半成品要和原成品、半成品BOM一致 2、创建拆解工单 CO01选择拆解工单的类型,以及填写拆解的物料和拆解工厂 维护工单组件 注意: 1、拆解入库组件的数量需要维护为负数 2、拆解工单投料组件数量维护为正数 3、拆解工单收发…...

《Python游戏编程入门》注-第4章2
《Python游戏编程入门》的“4.2.2 键盘事件”中介绍了通过键盘事件来监听键盘按键的方法。 1 键盘事件 玩家点击键盘中某个按键实际上包含了两个动作:点击按键和释放按键,也就是按键按下和松开。按键按下的对应的事件是KEYDOWN,按键松开对应…...

deque
deque 底层数据结构 动态开辟的二维数组第一维数组中存放的是第二维数组的指针每个第二维数组大小为512字节。假如存放的是**_Tp类型,每个第二维数组存放512/(sizeof(_Tp**))个元素按照第一维数组大小二倍进行扩容 举例 当deque进行push_back,将下半部分空间元素…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
基础测试工具使用经验
背景 vtune,perf, nsight system等基础测试工具,都是用过的,但是没有记录,都逐渐忘了。所以写这篇博客总结记录一下,只要以后发现新的用法,就记得来编辑补充一下 perf 比较基础的用法: 先改这…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)
设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile,新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join
纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...
Redis:现代应用开发的高效内存数据存储利器
一、Redis的起源与发展 Redis最初由意大利程序员Salvatore Sanfilippo在2009年开发,其初衷是为了满足他自己的一个项目需求,即需要一个高性能的键值存储系统来解决传统数据库在高并发场景下的性能瓶颈。随着项目的开源,Redis凭借其简单易用、…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...