C++标准模板库(STL)

本文深入解析C++标准模板库(STL)的核心概念,包括容器、迭代器、算法、容器适配器和函数对象。详细介绍了vector、map、multimap、set、multiset等容器的使用方法,以及sort、count、find等算法的通用操作。并通过具体示例展示了如何利用STL进行高效的数据管理和算法处理。

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

STL概述
STL是C++标准程序库的核心,深刻影响了标准程序库的整体结构
STL由一些可适应不同需求的集合类(collection class),以及在这些数据集合上操作的算法(algorithm)构成
STL内的所有组件都由模板(template)构成,其元素可以是任意类型
STL是所有C++编译器和所有操作系统平台都支持的一种库

STL组件
容器(Container) - 管理某类对象的集合
迭代器(Iterator) - 在对象集合上进行遍历
算法(Algorithm) - 处理集合内的元素
容器适配器(container adaptor)
函数对象(functor)
在这里插入图片描述
STL容器类别
序列式容器-排列次序取决于插入时机和位置
关联式容器-排列顺序取决于特定准则
在这里插入图片描述
STL容器的共同能力
所有容器中存放的都是值而非引用。如果希望存放的不是副本,容器元素只能是指针。
所有元素都形成一个次序(order),可以按相同的次序一次或多次遍历每个元素。

STL容器元素的条件:
必须能够通过拷贝构造函数进行复制
必须可以通过赋值运算符完成赋值操作
必须可以通过析构函数完称销毁动作
序列式容器元素的默认构造函数必须可用
某些动作必须定义operator ,例如搜寻操作
关联式容器必须定义出排序准则,默认情况是重载operator <

对于基本数据类型(int,long,char,double,…)而言,以上条件总是满足

STL容器的共同操作
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

迭代器(iterator)(示例:iterator)
可遍历STL容器内全部或部分元素的对象
指出容器中的一个特定位置
迭代器的基本操作
在这里插入图片描述
在这里插入图片描述
半开区间[beg, end)的好处:
1.为遍历元素时循环的结束时机提供了简单的判断依据(只要未到达end(),循环就可以继续)
2.不必对空区间采取特殊处理(空区间的begin()就等于end())
在这里插入图片描述
在这里插入图片描述

vector

  • vector模拟动态数组
  • vector的元素可以是任意类型T,但必须具备赋值和拷贝能力(具有public拷贝构造函数和重载的赋值操作符)
  • 必须包含的头文件 vector
  • vector支持随机存取
  • vector的大小(size)和容量(capacity), size返回实际元素个数,capacity返回vector能容纳的元素最大数量。如果插入元素时,元素个数超过capacity,需要重新配置内部存储器。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
#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应用实例:map
multimap应用实例:multimap

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; //example for user-defined class
    map<T2, int, cmp>mt2; //example for user-defined class(functor)
map<string, int> m2;
    map<string, int>::iterator m2i, p1, p2;
    //map<string, int, greater<string> >m2;
    //map<string, int, greater<string> >::iterator m2i, p1, p2; 
    m2["abd"] = 2;
    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()){
        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;
    }
}
int main(){
    multimap<string, int> mm1;
    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;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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, T2,cmp> s3;
#if 1
    set<string>s1;
    set<string>::iterator iter1;
#else
    set<string, greater<string> >s1;
    set<string, greater<string> >::iterator iter1;
#endif
    s1.insert("abc");
    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;
    }
    return 0;
}
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(){
    multiset<T1> s2;
    multiset<T2, T2cmp> s3;
#if 1
    multiset<string>s1;
    multiset<string>::iterator iter1;
#else
    multiset<string, greater<string> >s1;
    multiset<string, greater<string> >::iterator iter1;
#endif
    s1.insert("abc");
    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;
}

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

#include <set>
#include <iostream>
using namespace std;
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);
 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); 
 if( p.second ) 
  cout << "2) " << * (p.first)  << " inserted" << endl;
 else
  cout << "2) " << * (p.first)  << " not inserted" << endl;
}
//insert函数返回值是一个pair对象, 其first是被插入元素的迭代器,second代表是否成功插入了

输出:

  1. 2.1 3.7 4.2 9.5
  2. 9.5 not inserted
#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  << ",";
}

Algorithm(算法)
泛型算法通则:
所有算法的前两个参数都是一对iterators:[first,last),用来指出容器内一个范围内的元素。
每个算法的声明中,都表现出它所需要的最低层次的iterator类型。
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
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:

template<class FwdIt> 
FwdIt max_element(FwdIt first, FwdIt last); 

返回[first,last) 中最大(不小)元素的迭代器,以 “< ”作比较器

for_each

template<class InIt, class Fun> 
Fun for_each(InIt first, InIt last, Fun f); 

对[first,last)中的每个元素 e ,执行 f(e) , 要求 f(e)不能改变e

#include <vector>
#include <iostream>
#include <numeric>
#include <list>
#include <algorithm>
using namespace std;
class CLessThen9  {
public:
 bool operator()( int n) { return n < 9; }
};
void outputSquare(int value ) {  
     cout << value * value << " "; 
}
int 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);
 cout << endl << "3)";
 cout << count_if(v.begin(),v.end(),CLessThen9());
                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);
}

输出:
2)2
3)6
4)1
5)100
7) 10000 4 64 1 2500 9 64 81 100 4

排序和查找算法
1)find

template<class InIt, class T> 
InIt find(InIt first, InIt last, const T& val); 

返回区间 [first,last) 中的迭代器 i ,使得 * i == val
2) find_if

template<class InIt, class Pred> 
InIt find_if(InIt first, InIt last, Pred pr); 

返回区间 [first,last) 中的迭代器 i, 使得 pr(*i) == true
3) binary_search 折半查找,要求容器已经有序且支持随机访问迭代器,返回是否找到

template<class FwdIt, class T>
 bool binary_search(FwdIt first, FwdIt last, const T& val); 

上面这个版本,比较两个元素x,y 大小时, 看 x < y

template<class FwdIt, class T, class Pred> 
bool binary_search(FwdIt first, FwdIt last, const T& val, Pred pr); 

上面这个版本,比较两个元素x,y 大小时, 看 pr(x,y)

#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";
 }
}

输出:
(1) 8
(2) 3
(3) 9 found

  1. lower_bound,uper_bound, equal_range
    lower_bound:
template<class FwdIt, class T> 
FwdIt lower_bound(FwdIt first, FwdIt last, const T& val); 

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

upper_bound:

template<class FwdIt, class T>
 FwdIt upper_bound(FwdIt first, FwdIt last, const T& val); 

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

equal_range:

template<class FwdIt, class T> 
pair<FwdIt, FwdIt> equal_range(FwdIt first, FwdIt last, const T& val); 

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

5)sort 快速排序

template<class RanIt> 
void sort(RanIt first, RanIt last); 

按升序排序。判断x是否应比y靠前,就看 x < y 是否为true

template<class RanIt, class Pred>
void sort(RanIt first, RanIt last, Pred pr);

按升序排序。判断x是否应比y靠前,就看 pr(x,y) 是否为true

改变序列的算法unique

template<class FwdIt> 
FwdIt  unique(FwdIt first, FwdIt last); 

用 == 比较是否相等

template<class FwdIt, class Pred> 
FwdIt  unique(FwdIt first, FwdIt last, Pred pr);

用 pr 比较是否等
去除[first,last) 这个升序序列中的重复元素
返回值是迭代器,指向元素删除后的区间的最后一个元素的后面

reverse

template <class BidIt>
void reverse(BidIt first, BidIt last);

颠倒区间[first,last)顺序

实际应用

利用map进行查找

可以使用vector动态数组来存储原始信息,当需要查找的时候如果直接查找的话要一个一个的从头开始遍历,效率较低,借助map的键值对的特点,我们可以利用map来建立索引。
实现方法:在建立vector的同时,也同时将该元素插入到map容器中,map的first是待查找的关键字,second是该元素在vector中的下标。

如果是在导入数据时建立map,可以按照下面这样写:

vector.push_back(element);
mapname.insert(make_pair(element.getSname(), vector.size() - 1));

如果是在处理过程中构造或者重构map,按照以下的方式写:

 map1.clear();
 map2.clear();
 vector<T>::iterator it, first = vector.begin();
 for (it = vector.begin(); it != vector.end(); it++)
 {
  map1.insert(make_pair(it->getSname(), distance(first, it)));
  map2.insert(make_pair(it->getSno(), distance(first, it)));
  //map1.insert(make_pair(it->getSname(), it - vector.begin()));
  //map2.insert(make_pair(it->getSno(), it - vector.begin()));
 }

在查找时,如果结果唯一:

void Operation::findBookById(string id)
{
 multimap<string, int>::iterator it;
 it = bookid.find(id);
 if (it == bookid.end())
  return;
 else
  cout << book[it->second];
}

如果结果不唯一:要用到lower_bound(满足条件的下界)和upper_bound(满足条件的下界)然后遍历lower_bound到upper_bound之间

void Operation::findBookByName(string name)
{
 multimap<string, int>::iterator it, p1, p2, p;
 it = bookname.find(name);
 if (it == bookname.end())
  return;
 else {
  p1 = bookname.lower_bound(name);
  p2 = bookname.upper_bound(name);
  for (p = p1; p != p2; p++) {
   cout << book[p->second] << endl;
  }
 }
}

要注意:一旦vector发生变化(如删除了元素或者修改了元素的关键字),对应的map一定要相应变化,否则会使得map与vector之间不对应,查找时候会产生错误
而一般如果删除了元素,map是进行重构;如果修改了关键字,map将此元素删除后再在map的后面insert一个新的元素即可,因为map自带自动排序功能。

void Operation::rebuildBookMap()
{
 bookname.clear();
 bookid.clear();
 vector<Book>::iterator it, first = book.begin();
 for (it = book.begin(); it != book.end(); it++)
 {
  bookname.insert(make_pair(it->getBname(), distance(first, it)));
  bookid.insert(make_pair(it->getIsbn(), distance(first, it)));
  //bookname.insert(make_pair(it->getBname(), it-book.begin()));
  //bookid.insert(make_pair(it->getIsbn(), it - book.begin()));
 }
}
void Operation::modifyBook(string id)
{
 multimap<string, int>::iterator it;
 vector<Book>::iterator first = book.begin();
 string pre;
 it = bookid.find(id);
 if (it == bookid.end())
  return;
 else
 {
  pre = book[it->second].getIsbn();
  cin >> book[it->second];
  int index = it->second;
  if (book[it->second].getIsbn() != pre)
  {
   bookid.erase(it);
   bookid.insert((make_pair(book[index].getIsbn(), index)));
  }
  cout << book[index];
 }
}

利用find_if函数结合map实现模糊查找

string内部的find函数本身可以实现对任意子串的查找,也就实现了模糊查找。问题在于必须给map的first准确的关键字,否则会查不出来,这就需要对find_if函数的谓词函数进行改造。

template<class InIt, class Pred> 
InIt find_if(InIt first, InIt last, Pred pr); 

返回区间 [first,last) 中的迭代器 i, 使得 pr(*i) == true

为此,我构造了一个类,并重载了函数调用运算符,在其内部实现取子串查找。(STL中常常这样构造类)

class map_value_finder
{
public:
 map_value_finder(const string& cmp_string) :m_s_cmp_string(cmp_string) {}
 bool operator ()(const multimap<string,int>::value_type& pair)
 {
  int loc;
  loc=pair.first.find(m_s_cmp_string);
  if (loc != pair.first.npos)
   return true;
  return false;
 }
private:
 const string& m_s_cmp_string;
};
void Operation::fuzzyFindBname(string str)
{
 multimap<string, int>::iterator it, p1, p2, p, begin;
 p1 = bookname.begin();
 p2 = bookname.end();
 begin = p1;
 for (p = p1; p != p2; p++)
 {
  it = find_if(begin, bookname.end(), map_value_finder(str) );
  if (it == bookname.end())
   return;
  else
   cout << book[it->second] << endl;
  it++;
  begin = it;
 }
}

区间查找

可以利用lower_bound到upper_bound来实现上界和下界的值的确定,然后遍历其中的元素即可

void Operation::findBookByTime(string t1, string t2)
{
 multimap<string, int>::iterator it1, it2, p;
 it1 = booktime.lower_bound(t1);
 it2 = booktime.upper_bound(t2);
 for (p = it1; p != it2; p++)
 {
  cout << book[p->second] << endl;
 }
}

多条件组合查询

利用集合的交并集来实现,将所有的关键字全部查出来,取出其值(second)放入集合中,将多个条件产生的集合做交操作即可。
交操作的函数前四个参数分别代表待操作的集合的起始和结束点,最后一个参数表示将操作后的集合保存到哪里。

set_intersection(bpub.begin(), bpub.end(), bname.begin(), bname.end(), insert_iterator<vector<int>>(res, res.begin()));
void Operation::multifind(string str1,string str2)
{
 vector<int> res;
 vector<int>::iterator v;
 multiset<int> bpub;
 multiset<int> bname;
 multimap<string, int>::iterator it, p1, p2, p;
 it = bookpub.find(str1);
 if (it == bookpub.end())
  return;
 else {
  p1 = bookpub.lower_bound(str1);
  p2 = bookpub.upper_bound(str1);
  for (p = p1; p != p2; p++)
  {
   bpub.insert(p->second); 
  }
 }
 it = bookname.find(str2);
 if (it == bookname.end())
  return;
 else {
  p1 = bookname.lower_bound(str2);
  p2 = bookname.upper_bound(str2);
  for (p = p1; p != p2; p++)
  {
   bname.insert(p->second);
  }
 }
 set_intersection(bpub.begin(), bpub.end(), bname.begin(), bname.end(), insert_iterator<vector<int>>(res, res.begin()));
 for (v = res.begin(); v != res.end(); v++)
 {
  cout << book[*v]<<" ";
 }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值