C++学习笔记(十九)

一、vector容器

1. vector基本概念

功能:vector数据结构和数组非常相似,也称为单端数组

vector与普通数组区别:不同之处在于数组是静态空间,而vector可以动态扩展

动态扩展:并不是在原空间之后续接新空间,耳罩寻找更大的内存空间,然后将原数据拷贝到新空间,释放原空间

2. vector构造函数

函数原型:

vector<T> v;        // 采用模板实现类实现,默认构造函数

vector(v.begin(), v.end());        // 将v[begin(), end()) 区间中的元素拷贝给本身

vector(n, elem);        // 构造函数将n个elem拷贝给本身

vector(const vector &vec);        // 拷贝构造函数

#include <iostream>
#include <vector>using namespace std;void printVector(vector<int>&v)
{for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{// 1. 默认构造 无参构造vector<int>v1;for (int i = 0; i < 10; i++){v1.push_back(i);}printVector(v1);// 2. 通过区间方式构造vector<int>v2(v1.begin(), v1.end());printVector(v2);// 3. n个elem方式构造vector<int>v3(10, 100);printVector(v3);// 4. 拷贝构造vector<int>v4(v3);printVector(v4);
}int main(int argc, char* argv[])
{test01();return 0;
}

3. vector赋值操作

函数原型:

vector& operator=(const vector &vec);        // 重载等号操作符

assign(beg, end);        // 将[beg, end)区间中的数据拷贝赋值给本身

assign(n, elem);        // 将n个elem拷贝赋值给本身

#include <iostream>
#include <vector>using namespace std;void printVector(vector<int>&v)
{for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{vector<int>v1;for (int i = 0; i < 10; i++){v1.push_back(i);}printVector(v1);// 1. 等号赋值vector<int>v2;v2 = v1;printVector(v2);// 2. 区间赋值vector<int>v3;v3.assign(v1.begin(), v1.end());printVector(v3);// 3. n个elem赋值vector<int>v4;v4.assign(10, 100);printVector(v4);
}int main(int argc, char* argv[])
{test01();return 0;
}

4. vector容量和大小

对vector容器的容量和大小操作

函数原型:

empty();        // 判断容器是否为空

capacity();        // 容器的容量

size();        // 返回容器中元素的个数

resize(int num);        // 重新指定容器的长度为num,若容器变长,则以默认值填充新位置

                                 // 如果容器变短,则末尾超出容器长度的元素被删除

resize(int num, elem);        // 重新指定容器的长度为num,若容器变长,则以elem值填充新位置

                                           // 如果容器变短,则末尾超出容器长度的元素被删除

#include <iostream>
#include <vector>using namespace std;void printVector(vector<int>& v)
{for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{vector<int>v1;for (int i = 0; i < 10; i++){v1.push_back(i);}printVector(v1);if (v1.empty()){cout << "v1为空..." << endl;}else{cout << "v1不为空..." << endl;cout << "v1的容量为:" << v1.capacity() << endl;cout << "v1的元素个数为:" << v1.size() << endl;}v1.resize(16);printVector(v1);cout << "v1的容量为:" << v1.capacity() << endl;cout << "v1的元素个数为:" << v1.size() << endl;v1.resize(20,100);printVector(v1);cout << "v1的容量为:" << v1.capacity() << endl;cout << "v1的元素个数为:" << v1.size() << endl;v1.resize(5);printVector(v1);cout << "v1的容量为:" << v1.capacity() << endl;cout << "v1的元素个数为:" << v1.size() << endl;
}int main(int argc, char* argv[])
{test01();return 0;
}

5. vector插入和删除

函数原型:

push_back(ele);        // 尾部插入元素ele

pop_back();        // 删除最后一个元素

insert(const_iterator pos, ele);        // 迭代器指向位置pos插入元素ele

insert(const_iterator pos, int count, ele);        // 迭代器指向位置pos插入count个元素ele

erase(const_iterator pos);        // 删除迭代器指向的元素

erase(const_iterator start, const_iterator end);        // 删除迭代器从start到end之间的元素

clear();        // 删除容器中所有元素

#include <iostream>
#include <vector>using namespace std;void printVector(vector<int>& v)
{for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{vector<int>v1;// 尾插v1.push_back(10);v1.push_back(20);v1.push_back(30);v1.push_back(40);v1.push_back(50);// 遍历printVector(v1);// 尾删v1.pop_back();v1.pop_back();printVector(v1);// 插入v1.insert(v1.begin(), 100);printVector(v1);v1.insert(v1.begin(), 2, 66);printVector(v1);// 删除v1.erase(v1.begin());printVector(v1);v1.erase(v1.begin(), v1.begin()+2);printVector(v1);// 清空v1.clear();printVector(v1);
}int main(int argc, char* argv[])
{test01();return 0;
}

6. vector数据存取

函数原型:

at(int idx);        // 返回索引idx所指的数据

operator[idx];        // 返回索引idx所指的数据

front();        // 返回容器中第一个数据元素

back();        // 返回容器中最后一个数据元素

#include <iostream>
#include <vector>using namespace std;void printVector(vector<int>& v)
{for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{vector<int>v1;for (int i = 0; i < 10; i++){v1.push_back(i);}// 通过[]访问元素for (int i = 0; i < v1.size(); i++){cout << v1[i] << " ";}cout << endl;// 通过at访问元素for (int i = 0; i < v1.size(); i++){cout << v1.at(i) << " ";}cout << endl;cout << "第一个元素为:" << v1.front() << endl;cout << "最后一个元素为:" << v1.back() << endl;
}int main(int argc, char* argv[])
{test01();return 0;
}

7. vector互换容器

函数原型:

swap(vec);        // 将vec与本身的元素互换

#include <iostream>
#include <vector>using namespace std;void printVector(vector<int>& v)
{for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{vector<int>v1;for (int i = 0; i < 10; i++){v1.push_back(i);}vector<int>v2;v2.assign(10, 10);cout << "交换前:" << endl;cout << "v1:" << " ";printVector(v1);cout << "v2:" << " ";printVector(v2);v1.swap(v2);cout << "交换前:" << endl;cout << "v1:" << " ";printVector(v1);cout << "v2:" << " ";printVector(v2);
}// 实际用途(巧用swap可以收缩内存空间)
void test02()
{vector<int>v1;for (int i = 0; i < 100000; i++){v1.push_back(i);}cout << "v1的容量是:" << v1.capacity() << endl;cout << "v1的大小是:" << v1.size() << endl;v1.resize(3);cout << "v1的容量是:" << v1.capacity() << endl;cout << "v1的大小是:" << v1.size() << endl;// 巧用swap收缩内存vector<int>(v1).swap(v1);cout << "v1的容量是:" << v1.capacity() << endl;cout << "v1的大小是:" << v1.size() << endl;
}int main(int argc, char* argv[])
{test01();test02();return 0;
}

vector<int>(v1).swap(v1);

v1在resize后,容量非常大,元素个数只有3

vector<int>(v1) ——> 利用v1目前的元素个数初始化一个匿名对象

swap(v1) ——> 指针的交换,v1指向匿名对象,匿名对象指向v1,当前行执行结束就会自动回收

总结:swap可以使两个容器互换,可以达到实用的收缩内存效果

8. vector预留空间

减少vector在动态扩展容量时的扩展次数

函数原型:

reserve(int len);        // 容器预留len个元素长度,预留位置不初始化,元素不可访问

#include <iostream>
#include <vector>using namespace std;void printVector(vector<int>& v)
{for (vector<int>::iterator it = v.begin(); it != v.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{vector<int>v1;// 统计开辟次数int num = 0;int* p = NULL;for (int i = 0; i < 100000; i++){v1.push_back(i);if (p != &v1[0]){p = &v1[0];num++;}}cout << "test01中num:" << num << endl;
}void test02()
{vector<int>v1;// 统计开辟次数v1.reserve(100000);int num = 0;int* p = NULL;for (int i = 0; i < 100000; i++){v1.push_back(i);if (p != &v1[0]){p = &v1[0];num++;}}cout << "test02中num:" << num << endl;
}int main(int argc, char* argv[])
{test01();test02();return 0;
}

总结:如果数据量较大,可以一开始利用reserve预留空间

二、deque容器

1. deque基本概念

功能:双端数组,可以对头端进行插入删除操作

deque和vector区别:1)vector对于头部的插入删除效率低,数据量越大,效率越低

                                    2)deque相对而言,对头部的插入删除速度会比vector快

                                    3)vector访问元素时的速度会比deque快,这和两者内部实现有关 

deque内部工作原理:

deque内部有个中控器 ,维护每段缓冲区中的内容,缓冲区中存放真实数据

中控器维护的是每个缓冲区的地址,使得使用deque时想一片连续的内存空间

deque容器的迭代器也是支持随机访问的

2. deque构造函数

函数原型:

deque<T> deqT;        // 默认构造形式

deque(beg,end);        // 构造函数将[beg, end)区间中的元素拷贝给本身

deque(n, elem);        // 构造函数将n个elem拷贝给本身

deque(const deque &deq);        // 拷贝构造函数

#include <iostream>
#include <deque>using namespace std;void printDeque(const deque<int>& d)
{for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++){// *it = 100; 报错:const只读cout << *it << " ";}cout << endl;
}void test01()
{deque<int>d1;for (int i = 0; i < 10; i++){d1.push_back(i);}printDeque(d1);deque<int>d2(d1.begin(), d1.end());printDeque(d2);deque<int>d3(10, 100);printDeque(d3);deque<int>d4(d3);printDeque(d4);
}int main(int argc, char* argv[])
{test01();return 0;
}

3. deque赋值操作

函数原型:

deque& operator=(const deque &deq);        // 冲澡等号操作符

assign(beg,end);        // 将[beg, end)区间中的数据拷贝赋值给本身

assign(n,elem);        // 将n个elem拷贝复制给本身

#include <iostream>
#include <deque>using namespace std;void printDeque(const deque<int>& d)
{for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{deque<int>d1;for (int i = 0; i < 10; i++){d1.push_back(i);}printDeque(d1);deque<int>d2;d2 = d1;printDeque(d2);deque<int>d3;d3.assign(d2.begin(), d2.end());printDeque(d3);deque<int>d4;d4.assign(10, 100);printDeque(d4);
}int main(int argc, char* argv[])
{test01();return 0;
}

4. deque大小操作

函数原型:

deque.empty();        // 判断容器是否为空

deque.size();        // 返回容器中元素的个数

deque.resize(num);        // 重新指定容器的长度为num,若容器变长,则以默认值填充新位置

                                       // 如果容器变短,则末尾超出容器长度的元素被删除

deque.resize(num, elem);       // 重新指定容器的长度为num,若容器变长,则以默认值填充新位置

                                                // 如果容器变短,则末尾超出容器长度的元素被删除

#include <iostream>
#include <deque>using namespace std;void printDeque(const deque<int>& d)
{for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{deque<int>d1;for (int i = 0; i < 10; i++){d1.push_back(i);}printDeque(d1);if (d1.empty()){cout << "d1为空..." << endl;}else{cout << "d1不为空..." << endl;cout << "d1中元素的个数为:" << d1.size() << endl;}d1.resize(15);printDeque(d1);d1.resize(20,100);printDeque(d1);d1.resize(5);printDeque(d1);
}int main(int argc, char* argv[])
{test01();return 0;
}

5. deque插入和删除

函数原型:

两端插入操作:

push_back(elem);        // 在容器尾部添加一个数据

push_front(elem);        // 在容器头部添加一个数据

pop_back();        // 删除容器最后一个数据

pop_front();        // 删除容器第一个数据

指定位置操作:

insert(pos, elem);        // 在pos位置插入一个elem元素的拷贝,返回新数据的位置

insert(pos, n, elem);        // 在pos位置插入n个elem数据,无返回值

insert(pos, beg, end);        // 在pos位置插入[beg, end)区间的数据,无返回值

clear();        // 清空容器的所有数据

erase(beg, end);        // 删除[beg, end)区间的数据,返回下一个数据的位置

erase(pos);        // 删除pos位置的数据,返回下一个数据的位置

6. deque数据存取

at(int idx);        // 返回索引idx所指的数据

operator[idx];        // 返回索引idx所指的数据

front();        // 返回容器中第一个数据元素

back();        // 返回容器中最后一个数据元素

7. deque排序

算法:

使用时需要包含头文件:#include <algorithm>

sort(iterator beg, iterator end)        // 对beg和end区间内元素进行排序(默认从小到大)

对于支持随机访问的迭代器的容器,都可以利用sort算法直接对其进行排序

#include <iostream>
#include <deque>
#include <stdlib.h>
#include <algorithm>using namespace std;void printDeque(const deque<int>& d)
{for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++){cout << *it << " ";}cout << endl;
}void test01()
{deque<int>d1;for (int i = 0; i < 10; i++){d1.push_back(rand()%100);}cout << "排序前:";printDeque(d1);cout << endl;cout << "排序后:";sort(d1.begin(), d1.end());printDeque(d1);cout << endl;
}int main(int argc, char* argv[])
{test01();return 0;
}

三、STL案例

1. 案例描述

有五名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分和最低分,取平均分

2. 实现步骤

1)创建五名选手,放到vector中

2)遍历vector容器,取出来每一个选手,执行for循环,把十个评分存到deque容器中

3)sort算法对deque容器中分数排序,去除最高分和最低分

4)deque容器遍历,计算总分

5)获取平均分

3. 代码实现

#include <iostream>
#include <vector>
#include <string>
#include <deque>
#include <algorithm>
#include <ctime>using namespace std;// 选手类
class Person
{
public:Person(string name, float score){this->m_Name = name;this->m_Score = score;}string m_Name;float m_Score;
};// 创建选手
void createPerson(vector<Person>& v)
{string nameSeed = "ABCDE";for (int i = 0; i < 5; i++){string name = "选手";name += nameSeed[i];float score = 0;Person p(name, score);// 将创建好的选手对象放入容器v.push_back(p);}
}void setScore(vector<Person>& v)
{for (vector<Person>::iterator it = v.begin(); it != v.end(); it++){// 将评委的分数放入deque容器中deque<int>dscore;for (int i = 0; i < 10; i++){int score = rand() % 41 + 60; // 生成60-100的分数dscore.push_back(score);}// 测试/*cout << "姓名:" << (*it).m_Name << "分数:";for (deque<int>::iterator dit = dscore.begin(); dit != dscore.end(); dit++){cout << *dit << " ";}cout << endl;*/// 排序sort(dscore.begin(), dscore.end());// 去掉最高分和最低分dscore.pop_back();dscore.pop_front();// 获取平均分int sum = 0;for (deque<int>::iterator dit = dscore.begin(); dit != dscore.end(); dit++){sum += *dit;}float average = sum / dscore.size();// 将平均分赋值给选手(*it).m_Score = average;}
}void showScore(vector<Person>& v)
{for (vector<Person>::iterator it = v.begin(); it != v.end(); it++){cout << "姓名:" << (*it).m_Name << " " << "平均分" << (*it).m_Score << endl;}
}void test01()
{// 随机数种子srand((unsigned int)time(NULL));// 1.创建五名选手vector<Person>v;createPerson(v);// 测试/*for (vector<Person>::iterator it = v.begin(); it != v.end(); it++){cout << "--------------" << endl;cout << "姓名:" << (*it).m_Name << endl;cout << "平均分:" << (*it).m_Score << endl;}*/// 2.给五名选手打分setScore(v);// 3.显示最后得分showScore(v);
}int main(int argc, char* argv[])
{test01();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/334635.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于Js深拷贝的三种方法详细讲解

目录 前言 一、pandas是什么&#xff1f; 二、使用步骤 1.利用函数递归来实现深拷贝 2.利用引入lodash包 3.利用JSON字符串转换 总结 前言 当涉及到JavaScript数据拷贝的时候&#xff0c;深拷贝是一个非常关键的概念。在JavaScript中&#xff0c;对象和数组被认为是引用类型&a…

Python学习之路-Hello Python

Python学习之路-Hello Python Python解释器 简介 前面说到Python是解释型语言&#xff0c;Python解释器的作用就是用于"翻译"Python程序。Python规定了一个Python语法规则&#xff0c;根据该规则可编写Python解释器。 常见的Python解释器 CPython&#xff1a;官方…

2024年跨境电商上半年营销日历,建议收藏

2024年伊始&#xff0c;跨境电商开启新一轮的营销竞技&#xff0c;那么首先需要客户需求&#xff0c;节假日与用户需求息息相关&#xff0c;那么接下来小编为大家整理2024上半年海外都有哪些节日和假期&#xff1f;跨境卖家如何见针对营销日历选品&#xff0c;助力卖家把握2024…

1878_emacs company backend的选择尝试

Grey 全部学习内容汇总&#xff1a; GitHub - GreyZhang/editors_skills: Summary for some common editor skills I used. 1872_emacs company backend的选择尝试 从C语言开发的使用场景角度&#xff0c;通过测试尝试看看这个company的backend应该来如何配置。 主题由来介…

连接两个路由器的有线连法,关键时候可能会发挥不小的作用

路由器网桥连接两个或多个路由器&#xff0c;以扩展网络范围&#xff0c;提供额外的以太网端口和无线接入点。但在开始之前&#xff0c;你必须首先决定如何使用每个路由器。因此&#xff0c;你需要知道你想要实现什么&#xff0c;并清楚地了解你对每台设备的期望。 例如你想扩…

在VS Code中安装Copilot与安装其他扩展的方法一样,只需简单几步

GitHub Copilot是由OpenAI和GitHub开发的人工智能工具。它的目的是通过自动完成代码来帮助开发人员使用集成开发环境&#xff08;IDE&#xff09;&#xff0c;如Visual Studio Code。它目前仅作为技术预览版提供&#xff0c;因此只有在候补名单上被认可的用户才能访问它。对于用…

MP4转gif图片怎么操作?一个网站帮你搞定

Gif格式图片相较于视频它的体积更小&#xff0c;传播起来更方便。当我们手中有MP4格式的视频想要制作gif动画的时候应该怎么操作呢&#xff1f;通过使用mp4转换gif&#xff08;https://www.gif.cn/&#xff09;动图的工具&#xff0c;不用下载任何软件&#xff0c;手机也能在线…

基于Java SSM框架实现点餐系统网站系统项目【项目源码

基于java的SSM框架实现点餐系统网站系统演示 JAVA简介 JAVA语言是目前软件市场上应用最广泛的语言开发程序。可以在多种平台上运用的&#xff0c;兼容性比较强&#xff0c;适应市面上大多数操作系统&#xff0c;不会出现乱码的现像&#xff0c;其扩展性和维护性都更好&#xf…

09.面向对象进阶

面向对象进阶 在前面的章节我们已经了解了面向对象的入门知识&#xff0c;知道了如何定义类&#xff0c;如何创建对象以及如何给对象发消息。为了能够更好的使用面向对象编程思想进行程序开发&#xff0c;我们还需要对Python中的面向对象编程进行更为深入的了解。 property装…

Java进击框架:Spring-Web(八)

Java进击框架&#xff1a;Spring-Web&#xff08;八&#xff09; 前言DispatcherServlet拦截器异常视图解析重定向转发 语言环境日志 过滤器带注释的控制器声明映射请求其它注解验证 功能性端点URI Links异步请求CORSHTTP缓存视图技术MVC配置其他Web框架 前言 Spring Web MVC是…

亚马逊广告竞价影响大吗?亚马逊广告竞价设置方法?-站斧浏览器

亚马逊广告竞价影响大吗 频繁调整亚马逊广告竞价可能导致一些负面影响&#xff0c;包括&#xff1a; 广告权重重新评估&#xff1a; 每次调整都会导致亚马逊系统重新评估广告权重&#xff0c;如果调整后的权重下降&#xff0c;可能导致广告排名下降&#xff0c;PPC广告成本上…

24/01/09 qt work

1. 使用手动连接&#xff0c;将登录框中的取消按钮使用qt4版本的连接到自定义的槽函数中&#xff0c;在自定义的槽函数中调用关闭函数 将登录按钮使用qt5版本的连接到自定义的槽函数中&#xff0c;在槽函数中判断ui界面上输入的账号是否为"admin"&#xff0c;密码是…