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<int>())中,greater<int>是一个预定义的函数对象,实现降序排序。
⑤适配器(Adapters)------调整组件行为的"转换器"
适配器通过修改现有组件的接口,使其适配特定场景。例如:
容器适配器:stack(栈,基于deque实现)、queue(队列,基于deque实现);
迭代器适配器:reverse_iterator(反向迭代器,用于逆序遍历)。

①vector------动态数组(最常用)
核心特性:底层用连续内存存储,类似原生数组,但支持自动扩容。当容量不足时,会重新分配更大的内存(通常是原容量的1.5或2倍),并拷贝原有数据。T* data = new Tn;
优势:
随机访问(vi或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 arr10)类似,但更安全(封装了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()
-
-
- deque容器
-
deque容器与vector容器非常相似,采用的是动态内存管理的方式存储元素的,提供了随机访问的方法,有着和vector容器几乎相同的操作方法。

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

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

list容器是以双向链表形式实现的,list容器中的元素通过指针将前面的元素和后边的元素链接到一起。与vector容器和array容器相比,list容器通过迭代器获取元素和插入元素,使用list容器可以使用大量的算法,提高编程效率。list容器的不足之处是不能直接通过位置访问元素,只能从迭代器获取的位置获取元素。
#include <list>
#include <iostream>
using namespace std;
template<typename T>
void print(list<T> mylist) //定义函数模板,输出list容器元素
{
typename list<T>::iterator it; //创建list的iterator迭代器
for (it = mylist.begin(); it != mylist.end(); it++)
cout << *it << " ";
cout << endl;
}
int main() {
list<int> 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;
}
-
-
- 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)区间内的元素
-
-
- 关联容器概述
-
关联型容器所有元素都是经过排序的,关联型容器都是有序的。它的每一个元素都有一个键(key),容器中的元素是按照键的取值升序排列的。
关联型容器内部实现为一个二叉树,在二叉树中,每个元素都有一个父节点和两个子节点,左子树的所有元素都比自己小,右子树的所有元素都比自己大。

-
-
- 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 <set>
#include <iostream>
using namespace std;
int main() {
set<int, greater<int>> s; //创建一个set容器s,元素按降序排列
multiset<char> ms; //创建一个multiset容器ms
//向s中插入元素
pair<set<int>::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<int>::iterator its; //创建s容器的迭代器,用于获取元素
cout << "s容器中元素:";
for (its = s.begin(); its != s.end(); its++)
cout << *its << " ";
cout << endl;
multiset<char>::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;
}
-
-
- map和multimap容器
-
map与multimap中存储的是元素对(key-value),map和multimap容器通常也可理解为关联数组,可以使用键作为下标获取对应的值。关联的本质在于元素的值与某个特定的键相关联,而不是通过位置索引获取元素。
#include <map>
#include <iostream>
using namespace std;
void printm(map<char, double> mymap)//定义printm()函数输出map容器元素
{
pair<char, double> p; //创建pair对象,map中元素是成对的,也要成对输出
map<char, double>::iterator it; //定义迭代器
for (it = mymap.begin(); it != mymap.end(); it++)
{
p = (pair<char, double>) * it; //将迭代器指向的一对元素存放到p中
cout << p.first << "->" << p.second << endl; //输出一对元素
}
}
void printmt(multimap<int, string> mymul) //定义printmt()函数输出multimap容器
{
pair<int, string> p;
multimap<int, string>::iterator it;
for (it = mymul.begin(); it != mymul.end(); it++)
{
p = (pair<int, string>) * it;
cout << p.first << "->" << p.second << endl;
}
}
int main() {
map<char, double> m; //创建一个map容器
m'a' = 1.2;m'b' = 3.6;m'c' = 6.4;
m'd' = 0.8;m'e' = 5.3;m'f' = 3.6;
cout << "map: " << endl;
printm(m);
cout << "map中key = a的值:" << m.at('a') << endl;
cout << "map中key = f的元素出现次数:" << m.count('f') << endl;
multimap<int, string> mt; //创建一个multimap容器
mt.insert(pair<int, string>(1, "chuan"));
mt.insert(make_pair(1, "zhi"));
mt.insert(multimap<int, string>::value_type(3, "bo"));
mt.insert(multimap<int, string>::value_type(4, "ke"));
cout << endl << "multimap: " << endl;
printmt(mt);
cout << "multimap头部元素:";
pair<int, string> p;
p = (pair<int, string>) * mt.begin();
cout << p.first << "->" << p.second << endl;
cout << "multimap尾部元素: ";
p = (pair<int, string>) * (--mt.end());
cout << p.first << "->" << p.second << endl;
return 0;
}
-
-
- stack适配器
-
stack存储的元素具有后进先出的特点,stack提供了push()函数向容器中插入元素,同时提供了pop()函数将最后插入的元素从容器中移除。

#include <stack>
#include <vector>
#include <iostream>
using namespace std;
int main() {
vector <int >v = { 1,2,3 };
stack<int, vector <int >> s(v);
s.push(4);
s.emplace(5);
s.pop();
while (!s.empty()) {
cout << " " << s.top();
s.pop();
}
return 0;
}
-
-
- queue适配器
-
queue容器适配器是一个先进先出(FIFO)的存储结构,具有队列的特点。容器中的元素只能从一端使用push()函数进行插入,从另一端使用pop()函数进行删除, queue容器适配器不允许一次插入或删除多个元素,且不支持迭代器方法如begin()、rbegin()等。

#include <list>
#include <queue>
#include <iostream>
using namespace std;
int main() {
list <int >l = { 1,2,3 };
queue<int, list <int>> q(l);
q.push(4);
q.emplace(5);
q.pop();
cout << "第一个元素" << q.front() << endl;
cout << "最后一个元素" << q.back() << endl;
while (!q.empty()) {
cout << " " << q.front();
q.pop();
}
return 0;
}
-
-
- priority queue
-
priority_queue是优先队列,它是队列的一种,但priority_queue可以按照自定义的方式对队列中的数据进行动态排序。向优先队列中插入或删除元素时,优先队列会动态的调整,以保证队列有序。

#include <list>
#include <queue>
#include <iostream>
using namespace std;
class Comp {
public:
bool operator()(int x, int y) { return x > y; }
};
template<class T>
void print(T& q) {
while (!q.empty()) {
cout << q.top() << " "; q.pop();
}
cout << endl;
}
int main() {
priority_queue<int> q;
for (int n : { 1, 4, 9, 6, 7, 2, 8, 3, 5 }) q.push(n);
print(q);
priority_queue<int, vector<int>, greater<int>> q1;
for (int n : { 1, 4, 9, 6, 7, 2, 8, 3, 5 }) q1.push(n);
print(q1);
priority_queue<int, vector<int>, Comp> q2;
for (int n : { 1, 4, 9, 6, 7, 2, 8, 3, 5 }) q2.push(n);
print(q2);
return 0;
}
-
-
- 输入迭代器与输出迭代器
-
输入迭代器(Inputiterator),只能一次一个的向前读取元素,并按此顺序传回元素值,是不可重复的单向遍历。
输出迭代器(Outputiterator)与输入迭代器相反,其作用是将元素值逐个写入,即只能逐个元素赋值。输出迭代器也支持对序列进行单向遍历,当把迭代器移到下一个位置后,也不能保证之前的迭代器是有效的。
前向迭代器(Forwarditerator)是输入迭代器和输出迭代器的集合,具有输入迭代器和输出迭代器的全部功能。前向迭代器支持对序列进行可重复的单向遍历,可以多次解析一个迭代器指定的位置,因此可以对一个值进行多次读写。
双向迭代器是在单向迭代器的基础上增加了一个反向操作,就是它既可以前进,又可以后退,因此它比单向迭代器新增一个功能,进行自减操作,例如it--或者--it。
随机访问迭代器在双向迭代器的基础上,又支持直接将迭代器向前或向后移动n个元素,而且还支持比较运算的操作,因此随机访问迭代器的功能几乎和指针一样。
-
-
- 算法概述
-
STL中提供的所有算法都包含在三个头文件中:<algorithm>、<numeric>、<functional>。
● algorithm是最大的一个头文件,它由一大堆函数模板组成,其中涉及到的功能有比较、交换、查找、遍历、复制、修改、删除、合并、排序等。
● 头文件numeric很小,只包括几个在序列中进行简单数学运算的函数模板,以及加法和乘法在序列中的一些操作。
● 头文件functional中则定义了一些类模板,用于声明一些函数对象。
for_each()算法
for_each()属于非可变序列算法,此算法非常灵活,可以同时处理修改每一个元素,其函数定义如下所示:
template<typename InputIterator, typename Function>
for_each(InputIterator begin, InputIterator end, Function func);
for_each()算法对[begin, end)区间中的每个元素都调用func函数(对象)进行操作,它不会对区间中的元素做任何修改,也不会改变原来序列的元素次序。
find()算法
find()也属于非可变序列算法,用于在指定区间查找某一元素是否存在,其函数原型如下所示:
template<typename InputIterator, typename T>
InputIterator find(InputeIterator first, InputIterator last, const T& value);
find()算法用于在[begin, last)区间查找value元素是否存在,如果存在,就返回指向这个元素的迭代器,如果不存在,就返回end。
copy()算法
对于copy()函数,我们并不陌生,在讲解迭代器几次都用到了copy()函数,它的功能是完成元素的复制,其函数原型如下所示:
template<typename InputIterator, typename OutputIterator>
OutputIterator copy(InputIterator first, InputIterator last, OutputIterator DestBeg);
copy()函数实现将[first, last)区间的元素复制到另一个地方,这个地方的起始位置为DestBeg。
sort()算法
sort()属于可变序列算法,它支持对容器中的所有元素进行排序,函数的原型有如下两种形式:
template<typename RanIt> //第一种形式
void sort(RanIt first, RanIt last);
template<typename RanIt, typename Pred> //第二种形式
void sort(RanIt first, RanIt last, Pred op);
accumulate()算法
accumulate()算法属于数值算法,它的原型如下所示:
template<typename InputIterator, typename T> //第一种形式
T accumulate(InputIterator first, InputIterator last, T t);
template<typename InputIterator, typename T,typename Pred> //第二种形式
T accumulate(InputIterator first, InputIterator last, T t, Pred op);
accumulate()函数的功能是将[first, last)区间内的数值累加,累加的初始值为t,它的返回值是元素累加结果。第二种形式可以按照指定的规则将元素相加。
#include <vector>
#include <algorithm>
#include <numeric>
#include <iostream>
using namespace std;
template<class T>
class Multi { //类模板
private:
T value;
public:
Multi(const T& v) :value(v) {} //构造函数
void operator()(T& elem) const { elem *= value; } //重载()运算符
};
void print(int elem) { //打印元素
cout << elem << " ";
}
int main() {
int arr\[\] = { 21, 4, 55, 22, 46, 79, 9, 5, 78, 34, 100 };
vector<int> v;
v.assign(arr, arr + sizeof(arr) / sizeof(int)); //用数组给v容器赋值
//调用for_each()函数将容器中每个元素都乘以2
for_each(v.begin(), v.end(), Multi<int>(2));
//调用copy()构造函数将容器中元素输出
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
//调用find()算法查找容器中是否存在值为200的元素
vector<int>::iterator it = find(v.begin(), v.end(), 200);
if (it != v.end())
cout << "容器中有值为200的元素" << endl;
else
cout << "容器中不存在值为200的元素" << endl;
sort(v.begin(), v.end()); //调用sort()算法将容器中元素从小到大排列
cout << "排序之后:" << endl;
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
cout << endl;
int sum = accumulate(v.begin(), v.end(), 0); //累加容器中元素
cout << "sum = " << sum << endl;
return 0;
}
-
- 练习
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));这个