算法数组:基础内容随笔

数组是存放在<连续内存空间>上<类型相同> 的数据集合

支持随机访问 O(1)
数组的核心优势就是其随机访问能力,它允许我们通过索引直接、迅速地访问数组中的任意元素。

数组寻址公式:
address(arr[i]) = base_address(arr) + i * sizeof_element
假如我们有一个长度为5的int数组,其基地址是0x0053fbd4,要访问第五个元素,即arr[4],那么根据寻址公式就可以计算出地址:

address_arr[4] = 0x0053fbd4 + (4 * 4) = 0x0053fbe4

遍历数组方式:

for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++){
printf("%d", arr[i]);
}

使用C++的话,要注意vector 和 array的区别,vector的底层实现是array,严格来讲vector是容器,不是数组。

C++STL数组:
std::vector: 动态数组,提供快速随机访问。
std::array: 固定大小的数组,具有静态分配的内存。

std::deque
●基于动态数组:std::deque 是一个基于动态数组的序列容器,可以高效地从两端添加或删除元素。
●允许序列操作:可以快速地在队列的前端和后端添加或删除元素。
●时间复杂度:提供常数时间复杂度 (O(1)) 的前端和后端插入和删除操作。中间插入或删除操作可能需要 O(n) 时间。

  • deque(分段连续存储)
    核心结构:底层:一个指针数组(中控 map),每个指针指向一个固定大小的连续缓冲区。
    push_front/push_back 只需在当前块的前/后填充,块满了就分配新块并在中控 map 中加一个指针。随机访问:先算目标在第几个块(偏移量 / 块大小),再算块内位置(偏移量 % 块大小),两次除法就定位了,所以是 O(1)。中间插入需要移动元素,O(n)。
    image

一、std::vector 核心特性详解

  1. 它是封装动态数组的顺序容器,定义于头文件
  2. 内存管理:元素连续存储,内存自动按需扩容(1.5/2倍)将旧元素全部拷贝/移动过去后释放旧内存,不需要手动管理堆内存。
  • 在std::vector扩容时,如果元素类型提供了移动构造函数且该函数被声明为[noexcept],则会优先使用移动构造函数。否则,std::vector会使用拷贝构造函数进行元素的复制。
  1. 时间复杂度:随机访问:O(1),可以像普通数组一样用下标直接访问任意位置元素,尾部插入/删除:均摊O(1),性能极高,中间位置插入/删除:O(n),需要移动后续所有元素
  2. 实用优化技巧:如果提前知道元素总数量,可以调用reserve()预分配内存,完全避免运行时扩容的性能开销;不需要的预留空间可以通过shrink_to_fit()释放还给系统。
  • shrink_to_fit()会向编译器发起一个非强制请求,尝试****重新分配一块刚好能容纳当前所有元素的新内存,将数据移动/拷贝过去后释放旧的冗余内存。
  1. 适用场景:需要频繁随机访问、元素数量会动态变化、主要在尾部增删元素的场景,比如算法题中的临时数据存储、动态采集的传感器数据缓存等。
    image

二、std::array 核心特性详解
它是C++11引入的固定大小静态数组容器,定义于头文件

  1. 内存管理:大小在编译期就必须指定,内存是栈上静态分配的,完全没有动态内存分配的开销,性能和原生C数组几乎一致。
  2. 核心优势:比原生C数组更安全,自带size()、at()(带下标越界检查)、fill()等便捷接口,同时保留了原生数组连续内存、可直接转成裸指针传给C接口的特性。
  3. 时间复杂度:所有操作都是O(1),随机访问效率拉满。
  4. 适用场景:元素数量编译期就确定、追求极致性能的场景,比如存储高速轴承故障诊断里固定长度的采样窗口数据、RGB三原色值、固定维度的小矩阵等。

三、两者核心差异对比表
image

如果数据量是动态变化的优先选vector,如果是固定长度的小数据集优先选array,能获得更好的性能表现。

C++程序的内存主要分为栈区、堆区、全局/静态区、常量区和代码区。栈区由编译器自动管理,用于存储局部变量、函数参数等,其分配和释放遵循函数调用栈的规则,空间有限。堆区则由程序员通过new或malloc等操作动态申请和释放,空间相对较大。
对于数组而言,其存储位置取决于定义方式:

  • ● 在函数内部定义的静态数组(例如 int arr[10];),其内存由编译器在栈上自动分配,函数返回时自动释放。
  • ● 用new操作符动态创建的数组(例如 int* arr = new int[10];),其内存是在堆区分配的,需要程序员手动使用delete[]释放,否则可能导致内存泄漏。
  • ● 全局数组或静态局部数组(使用static关键字)则存储在全局/静态区。

内存相关补充:

  • 栈区的空间限制:Windows下默认栈空间通常只有1MB~8MB,Linux下一般是8MB左右,如果在函数内定义int arr[1000000]这种超大局部数组,很容易直接触发栈溢出崩溃,这也是工程里大数组必须用动态分配的核心原因。
  • 全局/静态区的细分:它还可以拆成两个子段:已初始化的全局/静态变量存在Data段,未初始化的会存在BSS段,系统会自动把BSS段的内存初始化为0,不需要程序员手动赋初值。
  • 常量区的只读属性:字符串字面量、const全局常量都存放在这里,操作系统会给这页内存加只读保护,尝试修改会直接触发段错误,比如写char* p = "hello"; p[0] = 'H'; 程序运行时会直接崩溃。
  • new和malloc的小区别:new不仅会在堆上分配内存,还会自动调用对象的构造函数,对应的delete[]会调用数组里所有元素的析构函数,这是C++面向对象特性在内存管理上的体现。
    image

-----随笔记录与学习,部分内容参考自网络,有疑问可以留言。>

posted @ 2026-07-07 11:44  icccey4  阅读(37)  评论(0)    收藏  举报