C++数据结构【顺序表和Vector】
顺序表的概念
定义:
线性表是n个具有相同特征的数据元素的有序序列。(比如数组,字符串)
1.每一个元素的类型都是一致的。
2.有先后顺序
3.逻辑结构:线性结构。
顺序表:用顺序存储的线性表
链表 :用链式存储的线性表
顺序表的模拟实现
可以通过数组采用动态申请和动态申请的方式来实现
动态实现:通过new和delete来申请和释放内存
int *a; //接受new出来的新地址
int capacity; //标记当前数组大小
int n; //记录数组中的有效个数
顺序表的动态实现
一、核心概念
顺序表的动态实现:通过动态内存分配(new/delete)调整数组容量,实现 “按需存储元素”。
二、结构定义(C++)
int *a; // 指向动态申请的数组的地址
int capacity; // 标记当前数组的容量(能存储的元素总数)
int n; // 标记当前有效元素的个数
三、扩容过程(插入 1~10 的示例)
目标:往顺序表末尾插入 10 个元素,初始容量不足时需多次扩容。
1. 第一次扩容(初始空间不足)
- 操作
a = new int[4]; // 申请能存4个int的空间 capacity = 4; // 容量更新为4
2. 第二次扩容(容量 4 存满后)
- 步骤:
- 申请 2 倍容量的新空间
int *t = new int[capacity * 2]; // 新容量=4*2=8 - 复制原数组元素到新空间
memcpy(t, a, sizeof(int) * capacity); // 把a的4个元素复制到t - 释放原空间 + 更新指针 / 容量
delete[] a; // 释放原数组内存 a = t; // a指向新数组 capacity *= 2; // 容量更新为8
- 申请 2 倍容量的新空间
3. 第三次扩容(容量 8 存满后)
- 重复第二次的逻辑,最终容量更新为 16(满足插入 10 个元素的需求)
int *t = new int[capacity * 2]; memcpy(t, a, sizeof(int) * capacity); delete[] a; a = t; capacity *= 2; // 容量更新为16
四、优缺点
| 特点 | 说明 |
|---|---|
| 优点 | 按需申请空间,避免内存浪费 |
| 缺点 | 扩容时需执行空间申请、元素复制、原空间释放,这些操作耗时,效率较低 |
顺序表的静态实现
int a[10000];
或者
const N = 10000; int a[N];
查找下标
1. 返回首次出现的下标
#include <iostream>
#include <vector>// 查找x在数组中首次出现的下标(数组用vector存储,更符合C++习惯)
int findFirst(const std::vector<int>& arr, int x) {for (int i = 0; i < arr.size(); ++i) {if (arr[i] == x) {return i; // 找到第一个匹配项即返回}}return -1; // 未找到返回-1(约定无效下标)
}// 测试示例
int main() {std::vector<int> arr = {2, 5, 3, 5, 1, 5};int target = 5;int firstPos = findFirst(arr, target);if (firstPos != -1) {std::cout << target << "首次出现的下标:" << firstPos << std::endl; // 输出:1} else {std::cout << "未找到" << target << std::endl;}return 0;
}
2. 返回最后出现的下标
#include <iostream>
#include <vector>// 查找x在数组中最后出现的下标
int findLast(const std::vector<int>& arr, int x) {int lastPos = -1; // 初始化为无效值for (int i = 0; i < arr.size(); ++i) {if (arr[i] == x) {lastPos = i; // 不断更新为最新匹配的下标}}return lastPos;
}// 测试示例
int main() {std::vector<int> arr = {2, 5, 3, 5, 1, 5};int target = 5;int lastPos = findLast(arr, target);if (lastPos != -1) {std::cout << target << "最后出现的下标:" << lastPos << std::endl; // 输出:5} else {std::cout << "未找到" << target << std::endl;}return 0;
}
3. 返回所有出现的下标(用 vector 存储结果)
#include <iostream>
#include <vector>// 查找x在数组中所有出现的下标,结果存入result
void findAll(const std::vector<int>& arr, int x, std::vector<int>& result) {result.clear(); // 清空原有结果for (int i = 0; i < arr.size(); ++i) {if (arr[i] == x) {result.push_back(i); // 收集所有匹配的下标}}
}// 测试示例
int main() {std::vector<int> arr = {2, 5, 3, 5, 1, 5};int target = 5;std::vector<int> allPos;findAll(arr, target, allPos);if (!allPos.empty()) {std::cout << target << "所有出现的下标:";for (int pos : allPos) {std::cout << pos << " "; // 输出:1 4 5}std::cout << std::endl;} else {std::cout << "未找到" << target << std::endl;}return 0;
}
关键说明
- 使用
std::vector替代原生数组:更安全(自动管理内存)、更灵活(可动态获取长度size()),符合 C++ 的现代编程习惯。 - 函数设计:
- 前两种需求直接返回
int类型下标(-1 表示未找到)。 - 第三种需求通过引用参数
std::vector<int>& result存储所有下标,避免返回值长度不确定的问题。
- 前两种需求直接返回
- 时间复杂度:均为O(n)(需遍历数组一次),空间复杂度除第三种为O(k)(k为重复次数)外,其余为O(1)。
Vector

swap
用于交换两个对象的值,核心总结如下:
标准库
std::swap:定义于<utility>,模板实现,通过移动语义(C++11 起)交换值,适用于所有可复制 / 移动的类型。自定义
swap:对含资源的自定义类型,可在类所在命名空间中重载,直接交换内部资源(如指针)以避免冗余拷贝,通过 ADL 机制优先调用。容器成员
swap:标准容器(如vector、string)自带成员函数,O (1) 时间复杂度交换内部数据,效率远高于std::swap,优先使用。注意:调用时建议通过
using std::swap; swap(a,b);形式,优先匹配自定义版本;自定义swap建议加noexcept。
