c++第九天 -- STL

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(反向迭代器,用于逆序遍历)。 ![](https://i-blog.csdnimg.cn/direct/c536db05b4a946559d3bf9fb649dadce.png) ①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容器几乎相同的操作方法。 ![](https://img-home.csdnimg.cn/images/20230724024159.png) deque容器的实现是一个双向队列,这是与vector容器最大的区别。deque容器不支持vector容器中的reserve()、capacity()和data()函数,其余函数均支持。deque容器新增的容器操作函数有pop_front()、push_front(),用于从队首和队尾弹出元素,emplace_back()从队尾添加元素。 1. 1. 1. **array容器** array是一个编译阶段确定大小的序列容器,是一个严格按照线性排序的特定数量元素的容器,大小与定义的数组是等效的。与其他容器不同的是,array大小固定,且没有分配容器空间、删除等操作。 ![](https://img-home.csdnimg.cn/images/20230724024159.png) 创建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相同,因此我们学习起来也比较容易。 ![](https://img-home.csdnimg.cn/images/20230724024159.png) 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容器只能向后迭代。 ![](https://img-home.csdnimg.cn/images/20230724024159.png) 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),容器中的元素是按照键的取值升序排列的。 关联型容器内部实现为一个二叉树,在二叉树中,每个元素都有一个父节点和两个子节点,左子树的所有元素都比自己小,右子树的所有元素都比自己大。 ![](https://img-home.csdnimg.cn/images/20230724024159.png) 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 \ #include \ using namespace std; void printm(map\ mymap)//定义printm()函数输出map容器元素 { pair\ p; //创建pair对象,map中元素是成对的,也要成对输出 map\::iterator it; //定义迭代器 for (it = mymap.begin(); it != mymap.end(); it++) { p = (pair\) \* it; //将迭代器指向的一对元素存放到p中 cout \<\< p.first \<\< "-\>" \<\< p.second \<\< endl; //输出一对元素 } } void printmt(multimap\ mymul) //定义printmt()函数输出multimap容器 { pair\ p; multimap\::iterator it; for (it = mymul.begin(); it != mymul.end(); it++) { p = (pair\) \* it; cout \<\< p.first \<\< "-\>" \<\< p.second \<\< endl; } } int main() { map\ 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\ mt; //创建一个multimap容器 mt.insert(pair\(1, "chuan")); mt.insert(make_pair(1, "zhi")); mt.insert(multimap\::value_type(3, "bo")); mt.insert(multimap\::value_type(4, "ke")); cout \<\< endl \<\< "multimap: " \<\< endl; printmt(mt); cout \<\< "multimap头部元素:"; pair\ p; p = (pair\) \* mt.begin(); cout \<\< p.first \<\< "-\>" \<\< p.second \<\< endl; cout \<\< "multimap尾部元素: "; p = (pair\) \* (--mt.end()); cout \<\< p.first \<\< "-\>" \<\< p.second \<\< endl; return 0; } 1. 1. 1. **stack适配器** stack存储的元素具有后进先出的特点,stack提供了push()函数向容器中插入元素,同时提供了pop()函数将最后插入的元素从容器中移除。 ![](https://img-home.csdnimg.cn/images/20230724024159.png) #include \ #include \ #include \ using namespace std; int main() { vector \v = { 1,2,3 }; stack\\> s(v); s.push(4); s.emplace(5); s.pop(); while (!s.empty()) { cout \<\< " " \<\< s.top(); s.pop(); } return 0; } 1. 1. 1. **queue适配器** queue容器适配器是一个先进先出(FIFO)的存储结构,具有队列的特点。容器中的元素只能从一端使用push()函数进行插入,从另一端使用pop()函数进行删除, queue容器适配器不允许一次插入或删除多个元素,且不支持迭代器方法如begin()、rbegin()等。 ![](https://img-home.csdnimg.cn/images/20230724024159.png) #include \ #include \ #include \ using namespace std; int main() { list \l = { 1,2,3 }; queue\\> 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; } 1. 1. 1. **priority queue** priority_queue是优先队列,它是队列的一种,但priority_queue可以按照自定义的方式对队列中的数据进行动态排序。向优先队列中插入或删除元素时,优先队列会动态的调整,以保证队列有序。 ![](https://img-home.csdnimg.cn/images/20230724024159.png) #include \ #include \ #include \ using namespace std; class Comp { public: bool operator()(int x, int y) { return x \> y; } }; template\ void print(T\& q) { while (!q.empty()) { cout \<\< q.top() \<\< " "; q.pop(); } cout \<\< endl; } int main() { priority_queue\ q; for (int n : { 1, 4, 9, 6, 7, 2, 8, 3, 5 }) q.push(n); print(q); priority_queue\, greater\\> q1; for (int n : { 1, 4, 9, 6, 7, 2, 8, 3, 5 }) q1.push(n); print(q1); priority_queue\, Comp\> q2; for (int n : { 1, 4, 9, 6, 7, 2, 8, 3, 5 }) q2.push(n); print(q2); return 0; } 1. 1. 1. **输入迭代器与输出迭代器** 输入迭代器(Inputiterator),只能一次一个的向前读取元素,并按此顺序传回元素值,是不可重复的单向遍历。 输出迭代器(Outputiterator)与输入迭代器相反,其作用是将元素值逐个写入,即只能逐个元素赋值。输出迭代器也支持对序列进行单向遍历,当把迭代器移到下一个位置后,也不能保证之前的迭代器是有效的。 前向迭代器(Forwarditerator)是输入迭代器和输出迭代器的集合,具有输入迭代器和输出迭代器的全部功能。前向迭代器支持对序列进行可重复的单向遍历,可以多次解析一个迭代器指定的位置,因此可以对一个值进行多次读写。 双向迭代器是在单向迭代器的基础上增加了一个反向操作,就是它既可以前进,又可以后退,因此它比单向迭代器新增一个功能,进行自减操作,例如it--或者--it。 随机访问迭代器在双向迭代器的基础上,又支持直接将迭代器向前或向后移动n个元素,而且还支持比较运算的操作,因此随机访问迭代器的功能几乎和指针一样。 1. 1. 1. **算法概述** STL中提供的所有算法都包含在三个头文件中:\、\、\。 ● algorithm是最大的一个头文件,它由一大堆函数模板组成,其中涉及到的功能有比较、交换、查找、遍历、复制、修改、删除、合并、排序等。 ● 头文件numeric很小,只包括几个在序列中进行简单数学运算的函数模板,以及加法和乘法在序列中的一些操作。 ● 头文件functional中则定义了一些类模板,用于声明一些函数对象。 for_each()算法 for_each()属于非可变序列算法,此算法非常灵活,可以同时处理修改每一个元素,其函数定义如下所示: template\ for_each(InputIterator begin, InputIterator end, Function func); for_each()算法对\[begin, end)区间中的每个元素都调用func函数(对象)进行操作,它不会对区间中的元素做任何修改,也不会改变原来序列的元素次序。 find()算法 find()也属于非可变序列算法,用于在指定区间查找某一元素是否存在,其函数原型如下所示: template\ InputIterator find(InputeIterator first, InputIterator last, const T\& value); find()算法用于在\[begin, last)区间查找value元素是否存在,如果存在,就返回指向这个元素的迭代器,如果不存在,就返回end。 copy()算法 对于copy()函数,我们并不陌生,在讲解迭代器几次都用到了copy()函数,它的功能是完成元素的复制,其函数原型如下所示: template\ OutputIterator copy(InputIterator first, InputIterator last, OutputIterator DestBeg); copy()函数实现将\[first, last)区间的元素复制到另一个地方,这个地方的起始位置为DestBeg。 sort()算法 sort()属于可变序列算法,它支持对容器中的所有元素进行排序,函数的原型有如下两种形式: template\ //第一种形式 void sort(RanIt first, RanIt last); template\ //第二种形式 void sort(RanIt first, RanIt last, Pred op); accumulate()算法 accumulate()算法属于数值算法,它的原型如下所示: template\ //第一种形式 T accumulate(InputIterator first, InputIterator last, T t); template\ //第二种形式 T accumulate(InputIterator first, InputIterator last, T t, Pred op); accumulate()函数的功能是将\[first, last)区间内的数值累加,累加的初始值为t,它的返回值是元素累加结果。第二种形式可以按照指定的规则将元素相加。 #include \ #include \ #include \ #include \ using namespace std; template\ 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\ v; v.assign(arr, arr + sizeof(arr) / sizeof(int)); //用数组给v容器赋值 //调用for_each()函数将容器中每个元素都乘以2 for_each(v.begin(), v.end(), Multi\(2)); //调用copy()构造函数将容器中元素输出 copy(v.begin(), v.end(), ostream_iterator\(cout, " ")); cout \<\< endl; //调用find()算法查找容器中是否存在值为200的元素 vector\::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\(cout, " ")); cout \<\< endl; int sum = accumulate(v.begin(), v.end(), 0); //累加容器中元素 cout \<\< "sum = " \<\< sum \<\< endl; return 0; } 1. 1. **练习** copy(v.begin(), v.end(), ostream_iterator\(cout, " "));这个