C++学习04:STL容器以及各迭代器的基本使用
文章目录
.撰写自己的算法和函数,结合容器和迭代器解决序列变换(如取反、平方、立方),像素变换(二值化、灰度拉伸);
2.用set存储学生信息,并进行增删改查操作;
3.输入一个字符串,用map统计每个字符出现的次数并输出字符及对应的次数。
做完请发表博客,上传博客链接
前言
C++应用最广泛的就是STL标准库提出的各个容器:向量vector,集合set,HashMap等等以及各个容器对应的迭代器。他们的使用使得C++对于数据的存储,处理变得十分方便,在本篇博客中,我们将介绍几个著名容器的使用方式,和对他们元素增删改查等操作。
1.使用vector容器和迭代器解决序列变换问题
1.1 创建vector容器,并进行赋值
我们这里使用vector容器存储数据。它是一个封装了动态大小数组的顺序容器。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组。向向量里传递数据也十分简单:
#include <iostream>
#include <vector>
#include<iterator>
#include<algorithm>
#include<functional>
#include<map>
#include<set>
#include<string>
int main(){
const int N =5;
vector<int> vecs(N); //向量里存储的数据类型必须一致
for(auto&vec:vecs)
cin>>vec; //利用auto自动输入元素
for(auto&vec:vecs)
cout<<vec<<" "; //循环输出元素查看是否赋值查看
}
在这些操作中,我们创建了一个容纳int类型的vector,然后循环向vector赋值,并循环输出值验证是否赋值准确。可以看到我们的赋值是成功的。
那么一般的我们在操作时,经常会对数据做一些变换,例如取反,图像二值化等等。对容器这样的操作常常需要对容器内部整个数据进行操作,那么循环取出数据,再一个个对数据进行处理速度太慢了。STL标准库的容器提供了transform方法。使得我们只需要简单地编写变换函数即可,而不需要去考虑如何取出容器的数据来操作,那么我们来使用一下这个方法吧。
1.2 使用自定义函数对容器数据进行操作
#include <iostream>
#include <vector>
#include<iterator>
#include<algorithm>
#include<functional>
#include<map>
#include<set>
#include<string>
using namespace std;
template <typename T> //使用模板类操作可以
T Cube(T x){
return x*x*x;
} // 对输入数据求立方操作
int main()
{
const int N =5;
vector<int> vecs(N);
for(auto&vec:vecs)
cin>>vec;
for(auto&vec:vecs)
cout<<vec<<" ";
cout<<endl;
// transform(vecs.begin(),vecs.end(),ostream_iterator<int>(cout," "),Cube<int>);
//transform输入
//将数据处理完之后传入输出流ostream_iterator
transform(vecs.begin(),vecs.end(),ostream_iterator<int>(cout," "),Cube<int>);
}
运行代码验证我们的数据处理是否正确:
可以看到我们成功的对输入数据1,2,3,4,5统一都取了立方操作。
我们还可以做一些简单的操作,如取平方,取负数等:
#include <iostream>
#include <vector>
#include<iterator>
#include<algorithm>
#include<functional>
#include<map>
#include<set>
#include<string>
typedef unsigned char uchar;
using namespace std;
template <typename T>
T square(T x){
return x*x;
} //返回平方
template <typename T>
T negative(T x){
return -x;
} //返回负数
template <typename T>
T Cube(T x){
return x*x*x;
}
int main()
{
const int N =5;
vector<int> vecs(N);
for(auto&vec:vecs)
cin>>vec;
for(auto&vec:vecs)
cout<<vec<<" ";
cout<<endl;
// transform(vecs.begin(),vecs.end(),ostream_iterator<int>(cout," "),Cube<int>);
transform(vecs.begin(),vecs.end(),ostream_iterator<int>(cout," "),Cube<int>);
cout<<endl;
transform(vecs.begin(),vecs.end(),ostream_iterator<int>(cout," "),negative<int>);
cout<<endl;
transform(vecs.begin(),vecs.end(),ostream_iterator<int>(cout," "),square<int>);}
我们在这里分别对数据进行了立方操作,取负数操作,平方操作:
2.使用set存储学生信息,并对数据进行增删改操作
set
是c++stl标准库实现的一个容器,能够给予数据进行自动排序。其基本的数据结构基于红黑树,因此其在插入和删除的效率上会更加快,但需要注意因为set的数据结构基于树节点存放数据,所以当我们使用循环遍历删除一个数据节点之后我们便无法访问该节点的子节点,再继续访问下去会报错(这点如果你不了解set的实现方式可能会遇到这个错误)。需要直接break退出循环。
那么接下来我们使用set结构存储学生姓名,然后一一使用增删改查操作。
#include <iostream>
#include <vector>
#include<iterator>
#include<algorithm>
#include<functional>
#include<map>
#include<set>
#include<string>
typedef unsigned char uchar;
using namespace std;
int main(){
set<string> my_Set;//Set的定义是用模板类定义的,所以这里也需要特化
my_Set.insert("LiLy"); //插入数据
my_Set.insert("XiaoMing");
my_Set.insert("shiPeng");
for(auto& s:my_Set)
cout<<s<<endl; //输出set内部内容
cout<<endl;
}
运行结果:
同时如果我们要删除和查找数据,这里我们直接使用set内置的函数即可:
#include <iostream>
#include <vector>
#include<iterator>
#include<algorithm>
#include<functional>
#include<map>
#include<set>
#include<string>
typedef unsigned char uchar;
using namespace std;
int main(){
set<string> my_Set;//Set的定义是用模板类定义的,所以这里也需要特化
my_Set.insert("LiLy"); //插入数据
my_Set.insert("XiaoMing");
my_Set.insert("shiPeng");
for(auto& s:my_Set)
cout<<s<<endl; //输出set内部内容
cout<<endl;
my_Set.erase("LiLy"); //删除LiLy这个数据
for(auto& s:my_Set) //输出删除数据后的set查看是否删除
cout<<s<<"\t";
cout<<endl;
if(my_Set.find("LiLy")!=my_Set.end()){ //find函数查找不到的时候会自动指向容器的底部
cout<<"find it "<<endl;
}
else{
//因为前面已经删除数据,所以这里应该是输出我找不到他
cout<<"I can't find it!"<<endl;
}
}
运行结果:
可以看到我们在set中成功删除了LiLy的名字,所以使用find方法,也无法查找到。
3.Map的应用
map比起直接翻译为映射,我更愿意认为他像python的’dict’字典类,它存储的数据结构,使用key-value等方式来进行存储。他在不少算法题中都应用非常广泛,我们今天就拿他来试一下这道题目:
“输入一个字符串,用map统计每个字符出现的次数并输出字符及对应的次数。”
#include <iostream>
#include <vector>
#include<iterator>
#include<algorithm>
#include<functional>
#include<map>
#include<set>
#include<string>
int main(){
string s ="aaaaacsbscddf"; //要统计出现字符次数的字符串
map<const char, int> newMap; //创立Map
for(auto&ch:s)
{
if(newMap.count(ch)>0) //查看Map内是否已经有该字符
newMap[ch]+=1;
else{
newMap.insert(pair<char,int>(ch,1)); //如果没有插入初始值为1
}
}
for (auto &kv : newMap) {
cout<<kv.first<<" has value "<<kv.second<<endl; //kv的first是key值,seconde是key对应的值
}
return 0;
}
最终我们利用字典key值唯一,且key值与关键值一一对应的特性,统计了该字符串内部各个字符出现的次数:
4. 如何对图像进行二值化等操作
这里,也是为即将到来的C++大作业做准备,这里我使用的是QT编辑器配置OPenCV 4.5.0包,(如何配置可以参照这个大佬的博客:Qt配置OpenCV教程,亲测已试过(详细版)_Wi~的博客-CSDN博客)
在这里我使用OpenCV来对图像进行二值化:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace cv;
using namespace std;
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main(){
Mat image=imread("C:\\Users\\admin\\Desktop\\unreal learn\\1.jpg",1); //一定要使用绝对路径,其他可以回报错
Mat result;
threshold(image, result, 100, 255, 0);
namedWindow("Display window", WINDOW_AUTOSIZE );
imshow( "Display window", image );
namedWindow("二值化后的图像1");
imshow("二值化后的图像1",result);
return 0;
}
结语
通过对本次实验的操作,我了解了STL标准库各个容器的基本使用方式,以及Opencv的基本使用方式,使用C++ 配合Opencv库进行图像处理将会使得图像处理速度加快。