cpp
复制代码
#include<iostream>
using namespace std;
class IntArray{
private:
int* data;
int size;
int capacity;
public:
IntArray() : data(nullptr),size(0),capacity(0) {}
~IntArray() {delete[] data;}
void append(int value){
if(size == capacity){
int newCap = capacity == 0 ? 4 : capacity * 2;
int* newData = new int[newCap];
for(int i = 0;i < size;++i) newData[i] = data[i];
delete[] data;
data = newData;
capacity = newCap;
}
data[size++] = value;
}
void printAll() const{
for(int i = 0;i < size;++i) cout << data[i] << " ";
cout << endl;
}
//这里就是插入排序
bool insert(int idx,int value){
if(idx < 0 || idx > size) return false;
append(0); //扩容
for(int i = size - 1;i > idx;--i) data[i] = data[i-1];
data[idx] = value;
return true;
}
bool remove(int idx){
if(idx < 0 || idx >= size) return false;
for(int i = idx;i < size - 1;++i) data[i] = data[i+1];
--size;
return true;
}
int& operator[](int idx) {return data[idx];}
int find(int value) const{
for(int i = 0; i < size;++i) if(data[i] == value) return i;
return -1;
}
void clear() {size = 0;}
int length() const {return size;}
};
int main()
{
IntArray arr;
int n;
cin >> n;
for(int i = 0;i < n;++i){
int num;
cin >> num;
arr.append(num);
}
arr.printAll();
//测试insert功能
int insertIndex,insertElement;
cin >> insertIndex >> insertElement;
if(arr.insert(insertIndex,insertElement)){
cout << "插入成功,插入后的数组: ";
arr.printAll();
}
else{
cout << "插入失败,索引位置不合法" << endl;
}
//测试remove功能
int removeIndex;
cin >> removeIndex;
if (arr.remove(removeIndex)) {
cout << "移除成功,移除后的数组: ";
arr.printAll();
}
else {
cout << "移除失败,索引位置不合法。" << endl;
}
// 测试 [] 功能
int accessIndex;
cin >> accessIndex;
cout << "访问结果: " << arr[accessIndex] << endl;
int newElement;
cin >> newElement;
cout << "查找元素 " << newElement << " 的位置: " << arr.find(newElement) << endl;
// 测试 clear 功能
arr.clear();
cout << "清空数组后,数组长度: " << arr.length() << endl;
cin >> newElement;
cout << "查找元素 " << newElement << " 的位置: " << arr.find(newElement) << endl;
return 0;
}
以期中测试的题目为例来体验模板的价值。
使用 C++ 语言设计并实现一个名为 IntArray 的类,该类用于封装一个整型数组,使用动态内存(即通过 new 和 delete 操作符)来存储整型数组元素。该类能实现的功能有:
append功能:在数组的末尾添加一个新的整型元素。如果数组容量不足,需要进行扩容操作。
insert功能:在指定的索引位置插入一个新的整型元素。如果索引位置不合法(小于 0 或者大于数组的当前元素数量),则不进行插入操作,并返回 false;如果数组容量不足,需要进行扩容操作。插入成功后返回 true。
remove功能:移除指定索引位置的元素。如果索引位置不合法(小于 0 或者大于等于数组的当前元素数量),则不进行移除操作,并返回 false;否则,移除元素并返回 true。移除元素后,后续元素需要向前移动。
\]功能:获取指定索引位置的元素。如果索引位置不合法(小于 0 或者大于等于数组的当前元素数量),则输出"error:out_of_range",同时返回0。
clear功能:移除数组中的所有元素。
length功能:返回数组中当前元素的数量。
find功能:在数组中查找指定的元素,返回该元素第一次出现的索引。如果未找到该元素,则返回 -1。
printAll功能:按顺序输出数组中的所有元素,元素之间用空格分隔,最后换行。
主函数输入初始整数的个数n,以及n个整数保存到整型数组对象中,然后分别调用对象的各个方法,验证功能的有效性。
主函数的代码已经给出,不要修改,在指定的位置完成IntArray类的代码即可。
STL主要由5大模块组成,彼此协同工作,形成"数据结构+算法"的高效解决方案:
①容器(Containers)------存储数据的"盒子"
容器是用于存储和组织数据的类模板,根据数据结构特性分为两类:
序列式容器:数据按插入顺序存储,元素位置与值无关(类似"数组")。常见类型:vector(动态数组,随机访问高效)、list(双向链表,插入删除高效)、deque(双端队列,头尾操作高效)。
关联式容器:数据按键值(Key)存储,支持快速查找(类似"字典")。常见类型:set(无重复元素的集合,默认排序)、map(键值对映射,默认按键排序);C++11后新增unordered_set/unordered_map(基于哈希表,查找平均O(1))。
②算法(Algorithms)------操作数据的"工具"
算法是处理容器中数据的通用函数模板,覆盖排序、查找、遍历、修改等常见操作,例如:
sort()(排序)、find()(查找)、reverse()(反转)、copy()(复制)、accumulate()(求和)。
算法不依赖具体容器类型,通过迭代器与容器解耦("算法操作迭代器,而非直接操作容器")。
③迭代器(Iterators)------连接容器与算法的"桥梁"
迭代器是一种类似指针的对象,用于遍历容器中的元素。它为不同容器提供统一的访问接口,让算法无需关心容器内部实现。
根据功能强弱,迭代器分为:输入/输出迭代器、前向迭代器、双向迭代器(如list)、随机访问迭代器(如vector)。
④函数对象(Function Objects,仿函数)------可调用的"自定义逻辑"
函数对象是重载了operator()的类或结构体,可作为参数传递给算法,实现自定义操作(如自定义排序规则)。
例如:sort(v.begin(), v.end(), greater\())中,greater\是一个预定义的函数对象,实现降序排序。
⑤适配器(Adapters)------调整组件行为的"转换器"
适配器通过修改现有组件的接口,使其适配特定场景。例如:
容器适配器:stack(栈,基于deque实现)、queue(队列,基于deque实现);
迭代器适配器:reverse_iterator(反向迭代器,用于逆序遍历)。

①vector------动态数组(最常用)
核心特性:底层用连续内存存储,类似原生数组,但支持自动扩容。当容量不足时,会重新分配更大的内存(通常是原容量的1.5或2倍),并拷贝原有数据。T\* data = new T\[n\];
优势:
随机访问(v\[i\]或v.at(i))效率极高(O(1));
尾部插入(push_back())均摊时间复杂度O(1)(仅扩容时O(n));
内存连续,对CPU缓存友好(比链表更快)。
劣势:
中间或头部插入/删除需移动元素(O(n));
扩容时可能导致原有迭代器/指针失效(因内存重新分配)。
典型场景:存储需要频繁访问的数据集(如用户列表、日志数组)。
②deque------双端队列
核心特性:底层由多个"块"(segment)组成的动态数组,每个块内部连续,块之间用指针连接,支持双端高效操作。
优势:
头尾插入/删除(push_front()/pop_front())时间复杂度O(1)(无需移动元素);
随机访问效率接近vector(O(1),通过块索引+块内偏移计算)。
劣势:
中间插入/删除仍需移动元素(O(n));
内存非完全连续,缓存利用率略低于vector。
典型场景:需要双端操作的场景(如任务队列、BFS遍历的队列)。
③list------双向链表
核心特性:底层是双向链表(每个节点包含前驱和后继指针),元素存储在非连续内存中。
优势:
任意位置插入/删除(insert()/erase())时间复杂度O(1)(仅需修改相邻节点指针);
插入/删除不影响其他元素的迭代器(除被删除元素外)。
劣势:
不支持随机访问(无法用\[\]或at(),只能通过迭代器顺序遍历);
内存开销大(每个元素需额外存储两个指针);
遍历效率低(非连续内存,缓存不友好)。
典型场景:需要频繁插入删除中间元素(如文本编辑器的撤销/重做链表)。
④forward_list------单向链表(C++11)
核心特性:底层是单向链表(每个节点仅含后继指针),比list更节省内存(无反向指针)。
优势:
内存占用更小(每个节点仅1个指针);
单向插入/删除操作与list同为O(1)。
劣势:
无法反向遍历(仅支持前向迭代器);
不支持size()操作(获取长度需遍历,O(n));
功能比list更受限(如无push_back(),仅支持push_front())。
典型场景:空间敏感且仅需单向操作(如简单的链式结构)。
⑤array------固定大小数组(C++11)
核心特性:底层是固定大小的连续数组(编译期确定大小),与原生数组(如int arr\[10\])类似,但更安全(封装了STL接口)。
优势:
随机访问O(1),性能与原生数组一致;
支持STL算法(如sort()、copy());
提供size()、front()、back()等安全接口(避免越界)。
劣势:
大小固定(无法动态调整);
不支持插入/删除操作(仅能修改元素值)。
典型场景:已知数据量且需高效访问(如固定长度的配置参数、坐标点数组)。
如何选择序列容器?
需要随机访问 → 优先选vector(数据增长主要在尾部)或deque(头尾需频繁操作);
需要中间频繁插入/删除 → 选list(双向操作)或forward_list(单向+空间敏感);
数据量固定 → 选array(替代原生数组,更安全);
内存效率 → vector(连续内存)\> deque(分段连续)\> list(双向链表)\> forward_list(单向链表)。
常用成员函数(方法):
vector提供了两个函数capacity()和size(),分别用于获取容器容量和容器实际元素个数:
v.capacity();
v.size();
访问某个元素:\[\]或.at()
v.front(); //获取容器头部元素(第一个元素)
v.back(); //获取容器尾部元素(最后一个元素)
从尾部插入和删除元素:push_back(T\& e) / pop_back()
1.
1.
1. **deque容器**
deque容器与vector容器非常相似,采用的是动态内存管理的方式存储元素的,提供了随机访问的方法,有着和vector容器几乎相同的操作方法。

deque容器的实现是一个双向队列,这是与vector容器最大的区别。deque容器不支持vector容器中的reserve()、capacity()和data()函数,其余函数均支持。deque容器新增的容器操作函数有pop_front()、push_front(),用于从队首和队尾弹出元素,emplace_back()从队尾添加元素。
1.
1.
1. **array容器**
array是一个编译阶段确定大小的序列容器,是一个严格按照线性排序的特定数量元素的容器,大小与定义的数组是等效的。与其他容器不同的是,array大小固定,且没有分配容器空间、删除等操作。

创建array容器
array容器由类模板定义,创建array容器的时候需要指定元素类型和元素个数,这是与vector定义不同的地方,示例代码如下:
array\a1; //定义array容器a1,未初始化
array\a1={1,2,3}; //定义array容器a2,使用列表初始化方式初始化
#include \
#include \
using namespace std;
int main()
{
array\c = { 1,2,3 };
array\c1 = { 2,3,4 };
array\::iterator pos;
c.swap(c1);
for (pos = c.begin();pos != c.end();++pos) {
cout \<\< \*pos \<\< " ";
}
return 0;
}
1.
1.
1. **list容器**
list容器是一个双向链表,因为同为序列式容器,所以它的接口大部分都与vector和deque相同,因此我们学习起来也比较容易。

list容器是以双向链表形式实现的,list容器中的元素通过指针将前面的元素和后边的元素链接到一起。与vector容器和array容器相比,list容器通过迭代器获取元素和插入元素,使用list容器可以使用大量的算法,提高编程效率。list容器的不足之处是不能直接通过位置访问元素,只能从迭代器获取的位置获取元素。
#include \
#include \
using namespace std;
template\
void print(list\ mylist) //定义函数模板,输出list容器元素
{
typename list\::iterator it; //创建list的iterator迭代器
for (it = mylist.begin(); it != mylist.end(); it++)
cout \<\< \*it \<\< " ";
cout \<\< endl;
}
int main() {
list\ lt; //创建空的list容器lt
for (int i = 0; i \< 10; i++)
lt.push_back(i + 1); //向容器中添加元素
cout \<\< "输出list容器中的元素:" \<\< endl;
print(lt); lt.pop_back(); //删除最后一个元素
lt.push_front(5); //在头部添加元素5
cout \<\< "再次输出list容器中的元素:" \<\< endl;
print(lt); lt.remove(5);
cout \<\< "删除5之后,输出list容器中的元素:" \<\< endl;
print(lt);
return 0;
}
1.
1.
1. **forward_list容器**
forward_list容器由单链表实现。在forward_list容器中,除了最后一个元素,每个元素与下一个元素通过指针链接。由于是单链表实现的,因此forward_list容器只能向后迭代。

forward_list容器不支持insert()函数和erase()函数,但它提供了insert_after()函数和erase_after()函数用于插入和删除元素。
insert_after(pos,val); //将元素val插入到pos位置之后
insert_after(pos,begin,end); //在pos位置插入\[begin,end)区间内的元素
erase_after(pos); //删除pos位置之后的元素
erase_after(begin,end); //删除\[begin,end)区间内的元素
1.
1.
1. **关联容器概述**
关联型容器所有元素都是经过排序的,关联型容器都是有序的。它的每一个元素都有一个键(key),容器中的元素是按照键的取值升序排列的。
关联型容器内部实现为一个二叉树,在二叉树中,每个元素都有一个父节点和两个子节点,左子树的所有元素都比自己小,右子树的所有元素都比自己大。

1.
1.
1. **set与multiset容器**
set与multiset都是集合,用于存储一组相同数据类型的元素。两者的区别是set用来存储一组无重复的元素,而multiset允许有重复的元素。
集合支持插入、删除、查找等操作,但集合中的元素值不可以直接修改,因为这些元素都是自动排序的,如果想修改某一个元素的值,必须先删除原有的元素,再插入新的元素。
set与multiset都重载了多个构造函数,因此创建set和multiset容器的方式有多种。
set与multiset还提供了查找函数find()和统计函数count()。
s.find(elem);
s.count(elem);
set与multiset提供了insert()函数与erase()函数,用于向容器中插入和删除元素。insert()函数主要有三种重载形式,分别如下所示:
s.insert(elem); //在容器中插入元素elem
s.insert(pos, elem); //在pos位置插入元素elem(pos是为了提高效率,如果pos不合适,就退化为普通的插入)
s.insert(begin, end); //在容器中插入\[begin, end)区间的元素
#include \
#include \
using namespace std;
int main() {
set\\> s; //创建一个set容器s,元素按降序排列
multiset\ ms; //创建一个multiset容器ms
//向s中插入元素
pair\::iterator, bool\> ps;
ps = s.insert(12);
if (ps.second == true)
cout \<\< "insert success" \<\< endl;
s.insert(39);
s.insert(32);
s.insert(26);
//向ms中插入元素
ms.insert('a');
ms.insert('z');
ms.insert('T');
ms.insert('u');
ms.insert('u');
//输出两个容器中的元素
set\::iterator its; //创建s容器的迭代器,用于获取元素
cout \<\< "s容器中元素:";
for (its = s.begin(); its != s.end(); its++)
cout \<\< \*its \<\< " ";
cout \<\< endl;
multiset\::iterator itms; //创建ms容器的迭代器
cout \<\< "ms容器中元素:";
for (itms = ms.begin(); itms != ms.end(); itms++)
cout \<\< \*itms \<\< " ";
cout \<\< endl;
//查找容器ms中元素u的个数
cout \<\< "ms容器中u元素个数:" \<\< ms.count('u') \<\< endl;
return 0;
}
1.
1.
1. **map和multimap容器**
map与multimap中存储的是元素对(key-value),map和multimap容器通常也可理解为关联数组,可以使用键作为下标获取对应的值。关联的本质在于元素的值与某个特定的键相关联,而不是通过位置索引获取元素。
#include \