c++STL学习笔记

本文深入解析C++标准模板库(STL)的六大组件,包括容器、算法和迭代器,探讨了vector、list、set、map等容器的特性和操作方法,以及泛型编程和算法的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

c++含义:C语言+类+模板(STL是实例,标准模板库)
STL有六大组件,常用的三个:容器(container),算法(algorithm),迭代器(iterator)
STL好处:节省时间,高移植性,高性能
STL内的所有组件都由模板(template)构成,其元素可以是任意类型
STL是所有C++编译器和所有操作系统平台都支持的一种库

容器:

  • 容器是系统帮我们封装好的数据结构(数组,链表【单向链表,双向链表】,栈,队列,数,hash表)
  • 每种结构都能装任意类型(模板,泛型编程)
  • 主要操作:增删改查
  • STL容器类别
    序列式容器-排列次序取决于插入时机和位置,vector,list,deque(线性顺序结构)
    关联式容器-排列顺序取决于特定准则set ,map(非线性的树结构)
  • STL容器元素的条件
    必须能够通过拷贝构造函数进行复制
    必须可以通过赋值运算符完成赋值操作
    必须可以通过析构函数完称销毁动作
    序列式容器元素的默认构造函数必须可用
    某些动作必须定义operator ==,例如搜寻操作
    关联式容器必须定义出排序准则,默认情况是重载operator <
    对于基本数据类型(int,long,char,double,…)而言,以上条件总是满足
  • STL容器的共同操作
    (1)初始化(initialization)
//产生一个空容器
std::list<int> l;
//以另一个容器元素为初值完成初始化
std::list<int> l;
…
std::vector<float> c(l.begin(),l.end());
//以数组元素为初值完成初始化
int array[]={2,4,6,1345};
…
std::set<int> c(array,array+sizeof(array)/sizeof(array[0]));
//sizeof(array)/sizeof(array[0])用整个数组所占空间除以第一个元素所占空间,结果为数组元素的个数

(2)与大小相关的操作(size operator)

size()-返回当前容器的元素数量
empty()-判断容器是否为空
max_size()-返回容器能容纳的最大元素数量

(3)比较(comparison)

==,!=,<,<=,>,>=

比较操作两端的容器必须属于同一类型
如果两个容器内的所有元素按序相等,那么这两个容器相等
采用字典式顺序判断某个容器是否小于另一个容器

(4)赋值(assignment)和交换(swap)

(5)与迭代器(iterator)相关的操作

begin()-返回一个迭代器,指向第一个元素
end()-返回一个迭代器,指向最后一个元素之后
//STL区间都是左闭右开
rbegin()-返回一个逆向迭代器,指向逆向遍历的第一个元素
rend()-返回一个逆向迭代器,指向逆向遍历的最后一个元素之后

(6) 元素操作

insert(pos,e)-将元素e的拷贝安插于迭代器pos所指的位置
erase(beg,end)-移除[beg,end]区间内的所有元素
clear()-移除所有元素

string

  • 专门字符串操作类
  • 与char* 的区别:char* 是指向字符串首地址的指针.然后系统提供了一个string.h头文件,声明了很多字符串操作,如:strlen,strcat,strcmp,srtcpy等。string则是个类,把以上内容封装在一起。string不需要考虑内存分配与释放。
  • 头文件:< string >
  • 构造函数:
    无参数构造函数:string();
    有参数构造函数:
 string(size_type length,char s);//length个s
 string (const char*str);//字符串初始化
 string(const char*str,size_type  length);//str的前几个
 string(string &str,size_type index,size_type length);//中间几个

拷贝构造:
string(const string& str);

	string s1;//调用无参构造
    string s2(10,'a');
    string s3("asdfg");
    string s4(s3);//拷贝构造
  • 操作
//取值操作
    string s1="1234";
//重载[]操作符
    for(int i=0;i<s1.size();i++)
    {
        cout<<s1[i]<<" ";
    }
 //at成员函数
    for(int i=0;i<s1.size();i++)
    {
        cout<<s1.at(i)<<" ";
    }
 //at与[]的区别:如果越界,at可以捕获异常,[]不可以
 //拼接操作
    s1=s2+s3;
    s4.append(s2);

查找,替换,比较:

//查找操作
string s="12342";
   cout<<s.find("34")<<endl;//find()方法,从前往后找第一次出现的位置
   cout<<s.rfind("2");//rfind()方法,从后往前找最后一次出现的位置
//替换操作
   string s="12342";
   cout<<s.replace(0,2,"aaaa");//结果aaaa342
//比较操作
    //compare,>返回1,<返回-1,==返回0
    string s1="1111";
    string s2="22";
    if(s1.compare(s2)==0)
      cout<<"字符串相等";
    cout<<"不相等";

删除,插入:

//string子串
    string s="asdfg";
    string s1=s.substr(1,2);
    cout<<s1<<endl;//结果sd

vector

  • vector模拟动态数组
  • 头文件#include < vector>
  • vector支持随机存取
  • vector的大小(size)和容量(capacity)
size()返回实际元素个数,
capacity()返回vector能容纳的元素最大数量。
如果插入元素时,元素个数超过capacity,需要重新配置内部存储器。
  • vector构造、拷贝和析构
    在这里插入图片描述
  • 非变动操作
    在这里插入图片描述

注意:比较的是向量本身。

  • 赋值操作
    在这里插入图片描述
  • 元素存取
    在这里插入图片描述
  • 与迭代器相关的操作
    在这里插入图片描述
  • 安插元素insert
    在这里插入图片描述
  • 移除元素remove
    在这里插入图片描述
#include <iostream>
int main(){
    vector<int> a;
    for (int i = 0; i < 5; ++i){
        a.push_back(5 - i);
    }
    cout << a.size() << endl;
    a.pop_back();
    a[0] = 1;
    cout << a.size() << endl;
    for (int i = 0; i < (int)a.size(); ++i){
        cout << a[i] << ", " << endl;//向量取元素时,可以以数组形式
    }    
    cout << endl;
    sort(a.begin(), a.end());//默认升序排序
    cout << "Size: " << a.size() << endl;
    for (int i = 0; i < (int)a.size(); ++i){
        cout << a[i] << ", " << endl;
    }
    cout << endl;

    a.clear();
    cout << "Size: " << a.size() << endl;
    return 0;
}

map/multimap

  • 使用平衡二叉树管理元素
    元素包含两部分(key,value),key和value可以是任意类型
  • #include < map >
  • 根据元素的key自动对元素排序,因此根据元素的key进行定位很快,但根据元素的value定位很慢
  • 不能直接改变元素的key,可以通过operator []直接存取元素值
  • map中不允许key相同的元素,multimap允许key相同的元素
  • 构造、拷贝和析构
    在这里插入图片描述
    map可以是下列形式
    map<key,value> 一个以less(<)为排序准则的map(升序),
    map<key,value,op> 一个以op为排序准则的map
  • 非变动操作List item
  • 赋值操作
    在这里插入图片描述
  • 特殊搜寻操作(除equal外,使用较多)
    在这里插入图片描述
  • 迭代器相关函数
    在这里插入图片描述
  • 安插元素
    在这里插入图片描述
  • 删除元素
    在这里插入图片描述
#include<bits/stdc++.h>
using namespace std;
struct T1{
    int v;
    bool operator<(const T1 &a)const{
        return (v < a.v);
    }
};

struct T2{
    int v;
};
struct cmp{
    const bool operator()(const T2 &a, const T2 &b){
        return (a.v < b.v);
    }
};
int main(){
    map<T1, int>mt1;
    map<T2, int, cmp>mt2;
    map<string, int> m2;
    map<string, int>::iterator m2i, p1, p2;
    m2["abd"] = 2;//map对象作为数组使用,下标为key的取值
    m2["abc"] = 1;
    m2["cba"] = 2;
    m2.insert(make_pair("aaa", 9));//成对
    m2["abf"] = 4;
    m2["abe"] = 2;
    cout << m2["abc"] << endl;
    m2i = m2.find("cba");
    if(m2i != m2.end()){
//first表示取出key,second表示取出value
        cout << m2i->first << ": " << m2i->second << endl;
    }else{
        cout << "find nothing" << endl;
    }
    cout << "Iterate" << endl;
    for(m2i = m2.begin(); m2i != m2.end(); m2i++){
        cout << m2i->first << ": " << m2i->second << endl;
    }
}

注意:
1.map对象放入元素的方式:
(1)作为数组,数组下标为关键字的取值,可为任意类型。
(2)map对象插入对象使用insert(make_pair())。
2.取出map对象的关键字和值元素,first表示取出key,second表示取出value.
#include<bits/stdc++.h>
using namespace std;
struct T1{
    int v;
    bool operator<(const T1 &a)const{
        return (v < a.v);
    }
};

struct T2{
    int v;
};
struct cmp{
    const bool operator()(const T2 &a, const T2 &b){
        return (a.v < b.v);
    }
};
int main(){
    multimap<string, int> mm1;
    //multiple存放关键字相同的若干元素
    multimap<string, int>::iterator mm1i, p1, p2;
    mm1.insert(make_pair("b", 3));
    mm1.insert(make_pair("a", 0));
    mm1.insert(make_pair("b", 5));
    mm1.insert(make_pair("c", 4));
    mm1.insert(make_pair("b", 2));
    cout << mm1.size() << endl;
    for(mm1i = mm1.begin(); mm1i != mm1.end(); mm1i++){
        cout << mm1i->first << ": " << mm1i->second << endl;
    }
    cout << "COUNT: " << mm1.count("b") << endl;
    cout << "Bound: " << endl;
//对满足条件的若干项查找
    p1 = mm1.lower_bound("b");//下限
    p2 = mm1.upper_bound("b");//上限
    for(mm1i = p1; mm1i != p2; mm1i++){
        cout << mm1i->first << ": " << mm1i->second << endl;
    }

    return 0;
}
注意:若要查找多个满足条件的项,先找到满足条件的上下限,再在满足条件的上下限区间中操作(输出)。

set/multiset

  • 使用平衡二叉树管理元素
  • 集合(Set)是一种包含已排序对象的关联容器。
  • 头文件#include < set>
  • map容器是键-值对的集合,好比以人名为键的地址和电话号码。相反地,**set容器只是单纯的键的集合。**当我们想知道某位用户是否存在时,使用set容器是最合适。
  • set中不允许key相同的元素,multiset允许key相同的元素
  • 在这里插入图片描述
    在这里插入图片描述
#include<bits/stdc++.h>
using namespace std;
struct T1{
    int key;
    int value1, value2;
    bool operator<(const T1 &b)const{
        return (key < b.key);
    }
};

struct T2{
    int key;
    int v1, v2;
};
struct T2cmp{
    bool operator()(const T2 &a, const T2 &b){
        return (a.key < b.key);
    }
};

int main(){
    set<T1> s2;
    set<T2, T2cmp> s3;

#if 1//宏定义条件编译
    set<string>s1;
    set<string>::iterator iter1;
#else
    set<string, greater<string> >s1;//两个>>之间要有空格!!!!!
    set<string, greater<string> >::iterator iter1;//greater降序排列
#endif
    s1.insert("abc");//set元素取值只能取不相同的
    s1.insert("abc");//无效
    s1.insert("abc");//无效
    s1.insert("bca");
    s1.insert("aaa");
cout << "ITERATE:" << endl;
    for (iter1 = s1.begin(); iter1 != s1.end(); iter1++)
        cout << (*iter1) << endl;
    cout << "FIND:" << endl;
    iter1 = s1.find("abc");
    if(iter1 != s1.end())
        cout << *iter1 << endl;
    else        cout << "NOT FOUND" << endl;
    cout << s1.count("abc") << endl;
    multiset<string>::iterator s1i, p1, p2;
    p1 = s1.lower_bound("abc");
    p2 = s1.upper_bound("abc");
    for(s1i = p1; s1i != p2; s1i++){
        cout << (*s1i) << endl;
    }
    return 0;
}
结果:
ITERATE:
aaa
abc
bca
FIND:
abc
1
abc
 注意:multiple可以允许插入值相同的元素,set中不能有值相同的元素。

pair 模板:
pair模板可以用于生成 key-value对。

#include <set>
#include <iostream>
using namespace std;
int main()  {
	typedef set<double,less<double> > double_set;
	const int SIZE = 5;
	double a[SIZE] = {2.1,4.2,9.5,2.1,3.7 };
	double_set doubleSet(a,a+SIZE);//数组元素初始化,把a中数据放入double_set中
	ostream_iterator<double> output(cout," ");
//输出流对象迭代器
	cout << "1) ";
	copy(doubleSet.begin(),doubleSet.end(),output);
	cout << endl;
pair<double_set::const_iterator, bool> p;
	p = doubleSet.insert(9.5); //插入不进去,已有9.5
	if( p.second ) 
		cout << "2) " << * (p.first)  << " inserted" << endl;
	else
		cout << "2) " << * (p.first)  << " not inserted" << endl;
}
//insert函数返回值是一个pair对象, 其first是被插入元素的迭代器,second代表是否成功插入了
#include <iostream>
#include <map>
using namespace std;

ostream & operator <<( ostream & o,const pair<  int,double> & p)
{
	o << "(" << p.first  << "," << p.second << ")";
	return o;
}
int main()  {
	typedef map<int,double,less<int> > mmid;
	mmid pairs;
	cout << "1) " << pairs.count(15) << endl;
	pairs.insert(mmid::value_type(15,2.7));
	pairs.insert(make_pair(15,99.3)); //make_pair生成一个pair对象
	cout << "2) " << pairs.count(15) << endl;
	pairs.insert(mmid::value_type(20,9.3));
	mmid::iterator i;
	cout << "3) ";
	for( i = pairs.begin(); i != pairs.end();i ++ )
		cout << * i  << ",";
cout << endl;
	cout << "4) ";
	int n =  pairs[40];//如果没有关键字为40的元素,则插入一个
	for( i = pairs.begin(); i != pairs.end();i ++ )
		cout << * i  << ",";
	cout << endl;
	cout << "5) ";
	pairs[15] = 6.28; //把关键字为15的元素值改成6.28
	for( i = pairs.begin(); i != pairs.end();i ++ )
		cout << * i  << ",";
}

迭代器:

链接容器和算法.可以理解为容器中元素的指针。
迭代器对象必须与容器类型相匹配

  • 可遍历STL容器内全部或部分元素的对象

  • 指出容器中的一个特定位置

  • 迭代器的基本操作
    在这里插入图片描述

  • 所有容器都提供获得迭代器的函数
    在这里插入图片描述
    半开区间[beg, end)的好处:
    1.为遍历元素时循环的结束时机提供了简单的判断依据(只要未到达end(),循环就可以继续)
    2.不必对空区间采取特殊处理(空区间的begin()就等于end())

  • 所有容器都提供两种迭代器
    container::iterator以“读/写”模式遍历元素
    container::const_iterator以“只读”模式遍历元素

  • 迭代器分类
    (1)双向迭代器
    双向行进,以递增运算前进或以递减运算后退、可以用==和!=比较。
    list、set和map提供双向迭代器

list<int> l; 
for(pos=l.begin();pos!=l.end();++pos{}

(2)随机存取迭代器
除了具备双向迭代器的所有属性,还具备随机访问能力。
可以对迭代器增加或减少一个偏移量、处理迭代器之间的距离或者使用<和>之类的关系运算符比较两个迭代器。
vector、deque和string提供随机存取迭代器

vector<int> v; 
for(pos=v.begin();pos<v.end();++pos{}

算法:

  • 系统帮我们写好的算法(排序,交换,替换等)
  • 一个算法可以适用多个容器(如,sort可以给数组排序,也可以给链表排序)
  • 泛型算法通则
    所有算法的前两个参数都是一对iterators:[first,last),用来指出容器内一个范围内的元素。
  • 常用算法:
count:
size_t count(InIt first, InIt last, const T& val); 
计算[first,last) 中等于val的元素个数

count_if 
size_t count_if(InIt first, InIt last, Pred pr); 
计算[first,last) 中符合pr(e) == true 的元素 e的个数

min_element:
template<class FwdIt> 
FwdIt min_element(FwdIt first, FwdIt last); 
返回[first,last) 中最小元素的迭代器,以 “< ”作比较器
max_element:
for_each
Fun for_each(InIt first, InIt last, Fun f); 对指定区间内的元素遍历
#include <vector>
#include <iostream>
#include <numeric>
#include <list>
#include <algorithm>
using namespace std;
class CLessThen9  {
public:
	bool operator()( int n) { return n < 9; }
};//<9返回true
void outputSquare(int value ) {  cout << value * value << " "; }
}
main() {
	const int SIZE = 10;
	 
	int a1[] = { 100,2,8,1,50,3,8,9,10,2 };
	vector<int> v(a1,a1+SIZE);
	ostream_iterator<int> output(cout," ");
	cout << endl << "2)";
	cout << count(v.begin(),v.end(),8);//数值为8的元素有几个
	cout << endl << "3)";
	cout << count_if(v.begin(),v.end(),CLessThen9());//<9的有几个
	cout << endl << "4)";
	cout << * (min_element(v.begin(),v.end()));
	cout << endl << "5)";
	cout << * (max_element(v.begin(),v.end()));
	cout << endl << "7) ";
	for_each(v.begin(),v.end(),outputSquare);
}

排序和查找算法

find(不属于某个容器对象的算法)
template<class InIt, class T> 
InIt find(InIt first, InIt last, const T& val); value重载了=运算符
返回区间 [first,last) 中的迭代器 i ,使得 * i == val

find_if
template<class InIt, class Pred> 
InIt find_if(InIt first, InIt last, Pred pr); 带条件的查询
返回区间 [first,last) 中的迭代器 i, 使得 pr(*i) == true

binary_search 折半查找,要求容器已经有序且支持随机访问迭代器,返回是否找到

lower_bound:
要求[first,last)是有序的,
查找大于等于val的最小的位置

upper_bound
要求[first,last)是有序的,
查找大于val的最小位置

equal_range
要求[first,last)是有序的,
返回值是一个pair, 假设为 p, 则
[first,p.first) 中的元素都比 val 小
[p.second,last)中的所有元素都比 val 大

sort   快速排序,升序

reverse   颠倒区间[first,last)顺序

unique    改变序列的算法
#include <vector>
#include <bitset>
#include <iostream>
#include <numeric>
#include <list>
#include <algorithm>
using namespace std;
bool Greater10(int n)
{
	return n > 10;
}
main()  {
	const int SIZE = 10;
	int a1[] = { 2,8,1,50,3,100,8,9,10,2 };
	vector<int> v(a1,a1+SIZE);
	ostream_iterator<int> output(cout," ");
	vector<int>::iterator location;
	location = find(v.begin(),v.end(),10);
	if( location != v.end()) {
		cout << endl << "1) " << location - v.begin();
	}//元素在向量中的位置
	location = find_if( v.begin(),v.end(),Greater10);
	if( location != v.end())
		cout << endl << "2) " << location - v.begin();
		sort(v.begin(),v.end());//先排序
	if( binary_search(v.begin(),v.end(),9)) {
		cout << endl << "3) " << "9 found";
	}
}

集合算法

#include "stdafx.h"
#include <iostream>
#include <set>
#include <algorithm>
#include <iterator> 

using namespace std;

template <class T>
struct display
{
	void operator()(const T&x) const
	{
		cout << x << " ";
	}
};

int main(int argc, char* argv[])
{
	int iarr1[] = { 1, 3, 5, 7, 9, 11 };
	int iarr2[] = { 1, 1, 2, 3, 5, 8, 13 };

	multiset<int> s1(iarr1, iarr1 + 6);
	multiset<int> s2(iarr2, iarr2 + 7);
	cout << "s1: ";
	for_each(s1.begin(), s1.end(), display<int>());
	cout << endl;
	cout << "s2: ";
	for_each(s2.begin(), s2.end(), display<int>());
	cout << endl;

	/*** set_union: 构造一个有序序列,包含两个序列中所有的不重复元素。 ***/
	//  原型: _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest)
	cout << "union of s1 and s2: ";
	// 两个集合合并,相同元素个数取 max(m,n)。   
	set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	/*** set_intersection: 构造一个有序序列,其中元素在两个序列中都存在。 ***/
	//  原型: _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest)
	cout << "Intersection of s1 and s2: ";
	// 两个集合交集,相同元素个数取 min(m,n).  
	set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	/*** set_difference: 构造一个有序序列,该序列仅保留第一个序列中存在的而第二个中不存在的元素。 ***/
	//  原型: _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest)
	cout << "Intersection of s1 and s2: ";
	// 两个集合差集 就是去掉S1中 的s2   
	set_difference(s1.begin(), s1.end(), s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	/*** set_symmetric_difference: 构造一个有序序列,该序列取两个序列的对称差集(并集-交集)。 ***/
	//  原型: _OutIt set_union(_InIt1 _First1, _InIt1 _Last1, _InIt2 _First2, _InIt2 _Last2, _OutIt _Dest)
	cout << "Intersection of s1 and s2: ";
	// 两个集合对称差集:就是取两个集合互相没有的元素 。两个排序区间,元素相等指针后移,不等输出小的并前进   
	// 相同元素的个数 abs(m-n)   
	set_symmetric_difference(s1.begin(), s1.end(), s2.begin(), s2.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	return 0;
}

/*
s1: 1 3 5 7 9 11
s2: 1 1 2 3 5 8 13
union of s1 and s2: 1 1 2 3 5 7 8 9 11 13
Intersection of s1 and s2: 1 3 5
Intersection of s1 and s2: 7 9 11
Intersection of s1 and s2: 1 2 7 8 9 11 13
*/

注意:
查找操作:
(1)精确查找
(2)模糊查找
(向量的按条件查找(效率较低))

  • 使用不完全的关键字。(对map对象的谓词函数中find_if())。
  • 区间查找:先找low_bound和up_bound,再操作区间里的元素。
  • 组合查找:多关键字查找。(满足条件较少的关键字,先作为第一关键字。)重合部分可以用集合算法(交集)。

学习感想:
经过这段时间的学习我对STL也有了大体的了解,但是STL内容掌握还不够熟练,内容还需要熟悉,多练习。接下来就要经过大量的训练来进一步扎实STL的运用。
最近学习状态有所松懈,作息也不够规律,还需调整提高效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值