NDK C++之 SLT 中的容器

460 阅读17分钟

C++之SLT中的容器

image.png

1. vector

vector(向量),是长度可以根据需要改变的数组。

1.1 定义

#include <iostream>
#include <vector> 
using namespace std;
vector<typename> name;
//例:
vector<double> v1;
vector<int> v2;
vector<char> v3;
vector<int> vector1;
vector<int> vector2(10); // 指定10的空间大小
vector<int> vector3(10, 0); // 有了10个值了 每个值都是0

注意:如果 typename也是一个STL容器,定义的时候要记得在>>符号之间加上空格,因为有的编译器可能会把它视为移位操作,导致编译错误。如下面定义二维数组。

#include <iostream>
#include <vector> 
using namespace std;
// vector数组:
vector<typename> arrayname[arraysize];
vector<int> v[100];	//一维长度已经固定为100
vector<vector<int> > name;	//两维的长度都可变

1.2 vecor内元组的访问

  • (1) 通过下标

vector[index]

#include <iostream>
#include <vector> 
using namespace std;

vector<int> vector4;
// vector4.begin() 迭代器 插入到前面
// vector4.end() 迭代器 插入到后面
 // 插入数据
 vector4.insert(vector4.begin(), 40);
 vector4.insert(vector4.begin(), 60);
 vector4.insert(vector4.begin(), 80);
 vector4.insert(vector4.begin(), 100);
 vector4.insert(vector4.begin(), 200);
 cout << "item:" << vector4[vector4.begin()] << endl;
  • (2) 通过迭代器

迭代器(iterator)可以理解为指针。vector::iterator it;

#include <iostream>
#include <vector> 
using namespace std;

vector<int> vector4;

 // vector4.begin() 迭代器 插入到前面
 // vector4.end() 迭代器 插入到后面

 // 插入数据
 vector4.insert(vector4.begin(), 40);
 vector4.insert(vector4.begin(), 60);
 vector4.insert(vector4.begin(), 80);
 vector4.insert(vector4.begin(), 100);
 vector4.insert(vector4.begin(), 200);
 // 第一个
 cout << " 修改前:vector4.front():" << vector4.front() << endl;
 vector4.front() = 99; // 默认修改第一个
 cout << " 修改后:vector4.front():" << vector4.front() << endl;

 // 最后一个
 cout << " 修改前:vector4.back():" << vector4.back() << endl;
 vector4.back() = 777; // 默认修改最后
 cout << " 修改后:vector4.back():" << vector4.back() << endl;

 vector4.erase(vector4.begin()); // 移除第一个元素(内部:通过迭代器的位置 进行移除) 
 // 循环打印,默认 从大到小输出
 for (int i = 0; i < vector4.size(); ++i) {
     cout << "item:" << vector4[i] << endl;
 }
 

1.3 常用函数

  • (1) push_back()

push_back(x)就是在vector后加一个元素x。

#include <iostream>
#include <vector> 
using namespace std;

vector<int> v;
v.push_back(10);//push_back(10)在v的末尾添加元素10
pop_back()用以删除vector的尾元素

  • (2) pop_back()

用以删除vector的尾元素

#include <iostream>
#include <vector> 
using namespace std;

vector<int> v;
v.insert(v.begin(), 40);
v.insert(v.begin(), 60);
v.pop_back();//用以删除vector的尾元素

  • (3) size()

size()用来获得vector中元素个数。

#include <iostream>
#include <vector> 
using namespace std;

vector<int> vector4;

 // vector4.begin() 迭代器 插入到前面
 // vector4.end() 迭代器 插入到后面

 // 插入数据
 vector4.insert(vector4.begin(), 40);
 vector4.insert(vector4.begin(), 60);
 vector4.insert(vector4.begin(), 80);
 vector4.insert(vector4.begin(), 100);
 vector4.insert(vector4.begin(), 200);

 // 循环打印,默认 从大到小输出
 for (int i = 0; i < vector4.size(); ++i) {
     cout << "item:" << vector4[i] << endl;
 }
 
  • (4) clear()

clear()用于清空vector中的所有元素。

#include <iostream>
#include <vector> 
using namespace std;

vector<int> vector4;

 // vector4.begin() 迭代器 插入到前面
 // vector4.end() 迭代器 插入到后面

 // 插入数据
 vector4.insert(vector4.begin(), 40);
 vector4.insert(vector4.begin(), 60);
 vector4.insert(vector4.begin(), 80);
 vector4.insert(vector4.begin(), 100);
 vector4.insert(vector4.begin(), 200);
 vector4.clear();//清空vector中的所有元素
  • (5) insert()

insert(it, x)用来向 vector的任意迭代器it处插入一个元素x。

#include <iostream>
#include <vector> 
using namespace std;

vector<int> vector4;

 // vector4.begin() 迭代器 插入到前面
 // vector4.end() 迭代器 插入到后面

 // 插入数据
 vector4.insert(vector4.begin(), 40);
 vector4.insert(vector4.begin(), 60);
 vector4.insert(vector4.begin(), 80);
 vector4.insert(vector4.begin(), 100);
 vector4.insert(vector4.begin(), 200);
  • (6) erase()

erase()有两种用法: 1. 删除单个元素: erase(i) 即删除迭代器为it处的元素。 2. 删除一个区间内所有的元素: erase(first, last) 即删除[first, last)内的所有元素。

#include <iostream>
#include <vector> 
using namespace std;

vector<int> vector4;

 // vector4.begin() 迭代器 插入到前面
 // vector4.end() 迭代器 插入到后面

 // 插入数据
 vector4.insert(vector4.begin(), 40);
 vector4.insert(vector4.begin(), 60);
 vector4.insert(vector4.begin(), 80);
 vector4.insert(vector4.begin(), 100);
 vector4.insert(vector4.begin(), 200);


 vector4.erase(vector4.begin()); // 移除第一个元素(内部:通过迭代器的位置 进行移除) 
 // 循环打印
 for (int i = 0; i < vector4.size(); ++i) {
     cout << "item:" << vector4[i] << endl;
 }
    
 vector4.erase(vector4.begin(),vector4.end()-1);
 // 迭代器 循环遍历
 for (auto iteratorVar = vector4.begin(); iteratorVar != vector4.end(); iteratorVar++) {
     // 迭代器 当中指针操作  iteratorVar++
     cout << "迭代器:" << *iteratorVar << endl;
 }

1.4 常见用途

  • (1) 存储数据

在一些元素不确定的场合可以使用。

  • (2) 用邻接表存储图

2. set

set翻译为集合,内部:红黑树结构)是一个内部自动有序且不含重复元素的容器。 set name;

set数组:set arrayname[arraysize];

2.1 定义

#include <iostream>
#include <set>
using namespace std;
set<int, less<int>> setVar; //  __x < __y 从小到大,默认情况下 就是 less

 // 添加参数,不需要用迭代器,也不需要指定位置
 setVar.insert(1);
 setVar.insert(3);
 setVar.insert(2);
 setVar.insert(4);

 // 重复插入,并不会报错  std::pair<iterator, bool>
 pair<set<int, less<int>>::iterator, bool> res = setVar.insert(8);

 // res.first 获取第一个元素 迭代器   当前迭代器   最后一个位置
 // res.second 获取第二个元素 bool
 bool insert_success = res.second;
 if (insert_success) {
     cout << "恭喜你,插入成功" << endl;
     // 插入成功后,我用第一个元素遍历
     for (; res.first != setVar.end(); res.first ++) {
         cout << *res.first << endl;
     }
 } else {
     cout << "哎,插入失败.." << endl;
 }

 // 全部遍历  auto 自动推到
 for (auto it = setVar.begin(); it != setVar.end() ; it ++) {
     cout << *it << endl;
 }

2.2 set内元素的访问

  #include <iostream>
  #include <set>
  using namespace std;
  set<int, less<int>> setVar; //  __x < __y 从小到大,默认情况下 就是 less

   // 添加参数,不需要用迭代器,也不需要指定位置
   setVar.insert(1);
   setVar.insert(3);
   setVar.insert(2);
   setVar.insert(4);

   // 重复插入,并不会报错  std::pair<iterator, bool>
   pair<set<int, less<int>>::iterator, bool> res = setVar.insert(8);

   // res.first 获取第一个元素 迭代器   当前迭代器   最后一个位置
   // res.second 获取第二个元素 bool
   bool insert_success = res.second;
   if (insert_success) {
       cout << "恭喜你,插入成功" << endl;
       // 插入成功后,我用第一个元素遍历
       for (; res.first != setVar.end(); res.first ++) {
           cout << *res.first << endl;
       }
   } else {
       cout << "哎,插入失败.." << endl;
   }

   // 全部遍历  auto 自动推到
   for (auto it = setVar.begin(); it != setVar.end() ; it ++) {
       cout << *it << endl;
   }

2.3 常用函数

  • (1) insert()

insert(x) 将x插入set容器中,并自动递增排序和去重。

  • (2) find()

find(value)返回set中对应值为value的迭代器,如果没找到则返回系统默认值。

  #include <iostream>
  #include <set>
  using namespace std;
  
  set<int> setVar; 

   // 添加参数,不需要用迭代器,也不需要指定位置
   setVar.insert(1);
   setVar.insert(3);
   setVar.insert(2);
   setVar.insert(4);

   const set<int>::iterator it = setVar.find(1);
   cout << *it << endl;
  • (3) size()

size()用来获得set中元素个数。

  • (4) clear()

clear()用于清空set中的所有元素。

  • (5) erase()

erase()有两种用法: 1. 删除单个元素: erase(it),it为所需要删除元素的迭代器,可结合find()函数使用。 erase(value),value为所需要删除的元素。 2. 删除一个区间内所有的元素: erase(first, last) 即删除[first, last)内的所有元素。

   #include <iostream>
   #include <set>
   using namespace std;
    
   set<int> setVar; 

   // 添加参数,不需要用迭代器,也不需要指定位置
   setVar.insert(1);
   setVar.insert(3);
   setVar.insert(2);
   setVar.insert(4);
   setVar.erase(2);
   setVar.erase(setVar.find(2),setVar.end());

    // 全部遍历  auto 自动推到
    for (auto it = setVar.begin(); it != setVar.end() ; it ++) {
        cout << *it << endl;
    }

2.4 set 谓词 设计对象的排序

// 谓词 设计对象的排序 

#include <iostream>
#include <set>
using namespace std;

class Person {
public:
    string name;
    int id;
    Person(string name, int id) : name(name), id(id) {}
};

// 真正的谓词
struct doCompareAction {
public:
    bool operator() (const Person& __x, const Person& __y) {
        return __x.id > __y.id;//id 大的排前面
    }
};

int main() {
    // 默认是 less  return 对象1 < 对象2;
    set<Person, doCompareAction> setVar;
    // 构建对象
    Person p1 ("小明", 1);
    Person p2 ("小美", 2);
    Person p3 ("小梅", 3);

    // 把构建的对象 插入到 set 容器里面去
    setVar.insert(p1);
    setVar.insert(p2);
    setVar.insert(p3);

    for (set<Person>::iterator it = setVar.begin(); it != setVar.end() ; it ++) {
        cout << it->name << " , " << it->id << endl;
    }
    return 0;
}

2.5 常见用途

遇到需要去重但不方便直接开数组的情况,可尝试用set解决。

3. string

 #include <iostream>
 #include <string>
 using namespace std;

3.1 定义

string str;

string str = "abcd";

3.2 string中内容的访问

  • (1) 通过下标

str[index] 如果要读入和输出整个字符串,则只能用cin和cout。

  • (2) 通过迭代器

string不想其他STL容器那样需要参数,因此可以直接如下定义:

string::iterator it;

string和vector一样,支持直接对迭代器进行加减,如str.begin() + 3。

3.3 常用函数

  • (1) +=

string的加法,可以将两个string直接拼接起来。

 #include <iostream>
 #include <string>

 using namespace std;

 int main() {
     string str1 = "abc", str2 = "xyz", str3;
     str3 = str1 + str2;
     str1 += str2;
     cout << str1 << endl;
     cout << str3 << endl;
     return 0;
 } 
  • (2) 比较

两个string类型可直接用==、!=、< 、<=、>、>=比较大小,比较规则是字典序(即"aac"小于"aba")。

  • (3) length()/size()

size()和length()基本相同

  • (4) insert()

1.insert(pos, string),在pos号位置插入string(从0开始)。

#include <iostream>
#include <string>
using namespace std; 
int main(){
	string str1 = "abcxyz", str2 = "opq";
	str1.insert(3, str2);
	cout << str1 << endl;
	return 0;
}

insert(it, it2, it3),it为原字符串的欲插入位置,it2和it3为待插字符串的首尾迭代器,表示[it2, it3)将被插在it的位置上。

#include <iostream>
#include <string>
using namespace std; 
int main(){
	string str1 = " Hi, girl!", str2 = "See you.";
	str1.insert(str1.begin(), str2.begin(), str2.end());
	cout << str1 << endl;
	return 0;
}
  • (5) erase()

删除单个元素:erase(i)即删除迭代器为it处的元素。

删除一个区间内所有的元素:

1.str.erase(first, last),其中first为区间的起始迭代器,
而last为需要删除的区间的末尾迭代器的下一个地址。

2.str.erase(pos, length),其中pos为需要开始删除的起始位置,
而length为删除的字符个数。
  • (6) clear()

clear()用于清空string中的所有元素。

  • (7) substr()

(8) substr(pos, len)返回从pos号开始、长度为len的子串。

string::npos string::npos是一个常数,其本身的值为-1,是unsighed_int类型。

string::npos用以作为find()函数失配时的返回值。

  • (9) find()

str.find(str2),

当str2是str的子串时,返回其在str中第一次出现的位置;

如果str2不是str的子串,则返回系统默认值

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "abc";
    stribf str2="b";
    unsigned long i = str.find(str2);
    cout << str[i] << endl;
    return 0;
}

str.find(str2, pos),从str的pos号开始匹配str2,返回值与上相同。

#include <iostream>
#include <string>

using namespace std;

int main() {
    string str = "Thank you for your help.";
    string str1 = "you";
    string str2 = "me";
    if(str.find(str1) != string::npos){
        cout << str.find(str1) << endl;
    }
    if(str.find(str1, 7) != string::npos){
        cout << str.find(str1, 7)<< endl;
    }
    if(str.find(str2) != string::npos){
        cout << str.find(str2) << endl;
    }else{
        cout << "There is no position for me." << endl;
    }
    return 0;
}
  • (9) replace()

str.replace(pos, len, str2)把str从pos位开始、长度为len的字符串换成str2.

str.replace(it1, it2, str2)把str的迭代器[it1, it2)范围的子串换成str2.

#include <iostream>
#include <string>
using namespace std; 
int main(){
	string str = "Thank you for your help.";
	string str1 = "HAPPY";
	string str2 = "BITE";
	cout << str.replace(10, 2, str1) << endl;
	cout << str.replace(str.begin(), str.begin() + 1, str2) << endl;
	return 0;
}

4. map

map可以将任何基本类型(包括STL容器)映射到任何基本类型(包括STL容器)。

4.1 定义

map<typename1, typename2> mp;

如果是字符串到整型的映射,必须使用string而不能用char数组:

map<string, int> mp;

map的键和值也可以是STL容器:

map<set<int>, string> mp;

4.2 map内内容的访问

  • (1) 通过下标

map中的键是唯一的。mp['key']

  • (2) 通过迭代器

map<typename1, typename2>::iterator it;

#include <iostream>
#include <map>

using namespace std;

int main() {
    map<char, int> mp;
    mp['a'] = 1;
    mp['b'] = 2;
    mp['c'] = 3;
     map<char, int>::iterator it = mp.find('b');
    cout <<"key:" << it->first<<" value:" <<it->second << endl;
    return 0;
}

4.3 常用函数

  • (1) find()
#include <iostream>
#include <map>

using namespace std;

int main() {
    map<char, int> mp;
    mp['a'] = 1;
    mp['b'] = 2;
    mp['c'] = 3;
     map<char, int>::iterator it = mp.find('b');
    cout <<"key:" << it->first<<" value:" <<it->second << endl;
    return 0;
}
  • (2) erase()

1.删除单个元素:

1.mp.erase(it),it为欲删除的元素的迭代器
2.mp.erase(key),key为欲删除的映射的键。
#include <iostream>
#include <map>

using namespace std;

int main() {
    map<char, int> mp;
    mp['a'] = 1;
    mp['b'] = 2;
    mp['c'] = 3;
    mp['d'] = 4;
    map<char, int>::iterator it = mp.find('b');
    mp.erase(it);	// 利用迭代器删除b 2
    mp.erase('c');	// 删除键为c的映射,即c 3
    for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++) {
        cout <<"key:" << it->first<<" value:" <<it->second << endl;
    }
    return 0;
}

删除一个区间内所有的元素:

mp.erase(first, last),删除[first, last)内的所有元素,first为起始迭代器,last为末尾迭代器的下一个地址。

#include <iostream>
#include <map>

using namespace std;

int main() {
    map<char, int> mp;
    mp['a'] = 1;
    mp['b'] = 2;
    mp['c'] = 3;
    map<char, int>::iterator it = mp.find('b');
    mp.erase(it, mp.end());
    for(map<char, int>::iterator it = mp.begin(); it != mp.end(); it++) {
        cout <<"key:" << it->first<<" value:" <<it->second << endl;
    }
    return 0;
}
  • (3) size()
  • (4) clear()

4.4 常见用处

1. 需要建立字符(或字符串)与整数之间映射的题目;
2. 判断大整数或其他类型数据是否存在的题目,可以把map当bool数组用;
3. 字符串和字符串的映射。

5. multimap

所谓“相似”,指的是 multimap 容器具有和 map 相同的特性,即 multimap 容器也用于存储 pair<const K, T> 类型的键值对(其中 K 表示键的类型,T 表示值的类型),其中各个键值对的键的值不能做修改;并且,该容器也会自行根据键的大小对存储的所有键值对做排序操作。和 map 容器的区别在于,multimap 容器中可以同时存储多(≥2)个键相同的键值对。

5.1 定义

通过调用 multimap 类模板的默认构造函数,可以创建一个空的 multimap 容器:

#include <iostream>
#include <map>

using namespace std;
//multimap 容器类模板的定义如下:
template < class Key,                                   // 指定键(key)的类型
           class T,                                     // 指定值(value)的类型
           class Compare = less<Key>,                   // 指定排序规则
           class Alloc = allocator<pair<const Key,T> >  // 指定分配器对象的类型
           > class multimap;
可以看到,multimap 容器模板有 4 个参数,其中后 2 个参数都设有默认值。
大多数场景中,我们只需要设定前 2 个参数的值,有些场景可能会用到第 3 个参数,
但最后一个参数几乎不会用到。

    // 注意:map会对key进行排序,默认 key不能重复
    map<int, string> mapVar;

    //  添加数据
    // 第一种方式
    mapVar.insert(pair<int, string>(1, "一"));

    // 第二种方式
    mapVar.insert(make_pair(2, "二"));

    // 第三种方式
    mapVar.insert(map<int, string>::value_type (3, "三"));

    // 上面三种方式 key不能重复
    // 思考:既然会对key进行排序,那么key是不能重复的(会插入失败)
    mapVar.insert(pair<int, string>(3, "三3"));

    // 第四种方式    mapVar[key]=Value
    mapVar[4] = "四";
    mapVar[4] = "肆"; // 第四种方式覆盖/替换(常用)

在创建 multimap 容器的同时,还可以进行初始化操作:

#include <iostream>
#include <map>
using namespace std;

int main() {
    //创建并初始化 multimap 容器
    multimap<int, string> mapVar{ {1, "http://c.biancheng.net/c/"},
                                        {2, "http://c.biancheng.net/python/"},
                                        {3, "http://c.biancheng.net/stl/"} };

    /**
     *  typedef typename _Rep_type::iterator		 iterator;  之前常规的迭代器
        typedef typename _Rep_type::const_iterator	 const_iterator;  只读的,只能读,不能修改 的迭代器
        typedef typename _Rep_type::reverse_iterator	 reverse_iterator;  倒序打印的迭代器
     */
    // 循环打印,迭代器
    for (map<int, string>::iterator it = mapVar.begin() ; it != mapVar.end() ; it ++) {
        cout << it->first << "," << it->second.c_str() << "\t";
    }
    cout << endl;
    return 0;
}

实际上,我们完全可以先手动创建好键值对,然后再用其初始化 multimap 容器。下面程序使用了 2 种方式创建 pair 类型键值对,再用其初始化 multimap 容器,它们是完全等价的:

  //创建并初始化 multimap 容器
    multimap<int, string> mapVar{ pair<int,string>{1, "Java"},
                                  pair<int,string>{2, "C++"},
                                  pair<int,string>{3, "Dart"} };
                                  
    multimap<int, string> mapVar{make_pair(1, "Java"),
                                 make_pair(2, "C++"),
                                 make_pair(3, "Dart")};

除此之外,通过调用 multimap 类模板的拷贝(复制)构造函数,也可以初始化新的 multimap 容器。例如:

  //创建并初始化 multimap 容器
    multimap<int, string> mapVar{ pair<int,string>{1, "Java"},
                                  pair<int,string>{2, "C++"},
                                  pair<int,string>{3, "Dart"} };

    multimap<int, string> newMapVar(mapVar);

multimap 类增添了移动构造函数。即当有临时的 multimap 容器作为参数初始化新 multimap 容器时,其底层就会调用移动构造函数来实现初始化操作。举个例子:

#include <iostream>
#include <map>

using namespace std;
//创建一个会返回临时 multimap 对象的函数
multimap<int, string> disMultiMap() {
    multimap<int, string> tempMultiMap{ 
        {4, "D"},
        {5, "F"} };
    return tempMultiMap;
}

int main() {
    //调用 multimap 类模板的移动构造函数创建 newMapVar 容器
    multimap<int, string> newMapVar(disMultiMap());
    /**
     *  typedef typename _Rep_type::iterator	iterator;  之前常规的迭代器
        typedef typename _Rep_type::const_iterator const_iterator;  只读的,只能读,不能修改 的迭代器
        typedef typename _Rep_type::reverse_iterator reverse_iterator;  倒序打印的迭代器
     */
    // 循环打印,迭代器
    for (map<int, string>::iterator it = mapVar.begin(); it != mapVar.end(); it++) {
        cout << it->first << "," << it->second.c_str() << "\t";
    }
    cout << endl;
    return 0;
}

multimap 类模板还支持从已有 multimap 容器中,选定某块区域内的所有键值对,用作初始化新 multimap 容器时使用。例如:

#include <iostream>
#include <map>

using namespace std;

int main() {
  multimap<int, string> mapVar{
            {3, "C"},
            {4, "D"},
            {5, "F"}};
    multimap<int, string> newMapVar(mapVar.begin(), mapVar.end());
    // 循环打印,迭代器
    for (map<int, string>::iterator it = mapVar.begin(); it != mapVar.end(); it++) {
        cout << it->first << "," << it->second.c_str() << "\t";
    }
}

multimap 类模板共可以接收 4 个参数,其中第 3 个参数可用来修改 multimap 容器内部的排序规则。默认情况下,此参数的值为std::less,这意味着以下 2 种创建 multimap 容器的方式是等价的:

#include <iostream>
#include <map>

using namespace std;

int main() {
    multimap<int, string> mapVar{
    {3, "C"},{4, "D"},{5, "F"}};
    // 循环打印,迭代器
    for (map<int, string>::iterator it = mapVar.begin(); it != mapVar.end(); it++) {
        cout << it->first << "," << it->second.c_str() << "\t";
    }
    cout << endl;
    multimap<int, string, less<int>> newMapVar{
    {3, "C"},{4, "D"},{5, "F"}};
    // 循环打印,迭代器
    for (map<int, string>::iterator it = newMapVar.begin(); it != newMapVar.end(); it++) {
        cout << it->first << "," << it->second.c_str() << "\t";
    }
    cout << endl;
    multimap<int, string, greater<int>> greaterMapVar{
     {3, "C"},{4, "D"},{5, "F"}};
    // 循环打印,迭代器
    for (map<int, string>::iterator it = greaterMapVar.begin(); it != greaterMapVar.end(); it++) {
        cout << it->first << "," << it->second.c_str() << "\t";
    }
    cout << endl;
    return 0;
}

5.2 成员方法

image.png

表 1 中部分成员方法的用法

#include <iostream>
#include <map>  //map
using namespace std;   
int main(){
    //创建并初始化 multimap 容器
    multimap<char, int>mymultimap{ {'a',10},{'b',20},{'b',15}, {'c',30} };
    //输出 mymultimap 容器存储键值对的数量
    cout << mymultimap.size() << endl;
    //输出 mymultimap 容器中存储键为 'b' 的键值对的数量
    cout << mymultimap.count('b') << endl;
    for (auto iter = mymultimap.begin(); iter != mymultimap.end(); ++iter) {
        cout << iter->first << " " << iter->second << endl;
    }
    return 0;
}
#include <iostream>
#include <map>

using namespace std;

int main() {
    // 1.key可以重复, 2.key重复的数据可以分组,  3.key会排序,  4.value不会排序
    multimap<int, string> multimapVar;

    multimapVar.insert(make_pair(10, "十个1"));
    multimapVar.insert(make_pair(10, "十个2"));
    multimapVar.insert(make_pair(10, "十个3"));

    multimapVar.insert(make_pair(30, "三十1"));
    multimapVar.insert(make_pair(30, "三十3"));
    multimapVar.insert(make_pair(30, "三十2"));


    multimapVar.insert(make_pair(20, "二十1"));
    multimapVar.insert(make_pair(20, "二十2"));
    multimapVar.insert(make_pair(20, "二十3"));

    for (auto iteratorVar = multimapVar.begin(); iteratorVar != multimapVar.end() ; iteratorVar ++) {
        cout << iteratorVar->first << "," << iteratorVar->second << endl;
    }
    cout << endl;

    //核心功能是分组
    int result;
    cout << "请输入你要查询的key,为int类型:" << endl;
    cin >> result;

    multimap<int, string>::iterator iteratorVar = multimapVar.find(result);
    while (iteratorVar != multimapVar.end()) {
        cout << iteratorVar->first << "," << iteratorVar->second << endl;
        // 需要自己做逻辑控制,不然有问题
        iteratorVar++;
        if (iteratorVar->first != result) {
            break;; // 循环结束
        }
        // 严谨性
        if (iteratorVar == multimapVar.end()) {
            break;; // 循环结束
        }
    }
    return 0;
}

6. queue

queue(队列)是STL中实现的一个先进先出的容器。

6.1 定义

queue<typename> name;

6.2 queue内内容的访问

因为队列是一种先进先出的数据结构,因此在SLT中只能用front()访问队首元素,通过back()访问队尾元素。

6.3 常用函数

  • (1) push()

push(x)将x压入队列

  • (2) front()、back()

front()用于访问队首元素,back()用于访问队尾元素。

#include <iostream>
#include <queue>

using namespace std;

int main() {
    queue<int> q;
    for (int i = 1; i <= 5; i++) {
        q.push(i);    //push(i)用以将i压入队列
    }
    cout << "first:" << q.front()<< " last:" << q.back() << endl;
    return 0;
}
  • (3) pop()

pop()令队首元素出队


#include <iostream>
#include <queue>

using namespace std;

int main() {
    queue<int> q;
    for (int i = 1; i <= 5; i++) {
        q.push(i);    //push(i)用以将i压入队列
    }
    for(int i = 1; i <= 3; i++) {
        q.pop();	//出队首元素3次(依次为1 2 3)
    }
    cout << "first:" << q.front()<< " last:" << q.back() << endl;
    return 0;
}
  • (4) empty()

empty()检测 queue是否为空,返回true则空,返回false则非空。

#include <iostream>
#include <queue>

using namespace std;

int main() {
    queue<int> q;
    if(q.empty()){
        cout << "Empty" << endl;
    }else{
        cout << "Not Empty" << endl;
    }
    q.push(1);
    if(q.empty()){
        cout << "Empty" << endl;
    }else{
        cout << "Not Empty" << endl;
    }
    return 0;
}
  • (5) size()

6.4 常见用处

当需要实现广度优先搜索时,可以不用自己手动实现一个队列,而是用queue作为代替,以提高程序的准确性。

**注意:**使用front()和pop()函数前,必须用empty()判断队列是否为空。

7. priority_queue

priority_queue又叫优先队列,其底层是用堆进行实现的。队首元素一定是当前队列中优先级最高的那一个。

可以在任何时间往优先队列里加入(push)元素,优先队列底层的堆(heap)会随时调整结构,使得每次的队首元素都是优先最大的。

关于这里的优先级则是规定出来的。

7.1 定义

#include <iostream>
#include <queue>

using namespace std;

priority_queue<typename> name;

7.2 priority_queue内内容的访问

和queue不同,priority_queue没有front()和back()函数,

只能通过top()函数来访问队首元素(堆顶元素),也就是优先级最高的元素。

#include <iostream>
#include <queue>

using namespace std;

int main() {
    priority_queue<int> q;
    q.push(1);
    q.push(4);
    q.push(5);

    cout << q.top() << endl;
    return 0;
}

7.3 常用函数

  • (1) push()
  • (2) top()

获得队首元素(即堆顶元素)出队。

  • (3) pop()
#include <iostream>
#include <queue>

using namespace std;

int main() {
    priority_queue<int> q;
    q.push(1);
    q.push(4);
    q.push(5);

    cout << q.top() << endl;
    q.pop();
    cout << q.top() << endl;
    return 0;
}
  • (4) empty()
  • (5) size()

7.4 priority_queue内元素优先级的设置

  • (1) 基本数据类型
此处指的基本数据类型就是int型、 double型、char型等可以直接使用的数据类型,
优先队列对他们的优先级设置一般是数字大的优先级越高。

下面两种定义方式是等价的(注意最后两个>之间有一个空格):
priority_queue<int> q;

priority_queue<int, vector<int>, less<int> > q;

第二种定义方法尖括号内多了两个参数:

vector<int>填写的是来承载底层数据结构堆(heap)的容器。
如果第一个参数是double型或char型,则此处只需填写vector<double>或vector<char>;

less<int>是对第一个参数的比较类。less<int>表示数字大的优先级越大,
而greater<int>表示数字小的优先级越大。

#include <stdio.h>
#include <queue> 
using namespace std;
int main(void){
    priority_queue<int, vector<int>, greater<int> > q;	//让优先队列总是把最小的元素放队首
    q.push(3);
    q.push(4);
	q.push(1);
	printf("%d\n", q.top());
    return 0;
}

  • (2) 结构体
通过改变小于号"<"的功能,即把它重载(overload)为大于号的功能。

现在希望按水果的价格高的为优先级高,需要重载小于号:
struct fruit {
	string name;
	int price;
   // friend为友元,bool operator < (fruit f1, fruit f2)对fruit类型的操作符"<"进行重载
	friend bool operator < (fruit f1, fruit f2) { 
		return f1.price < f2.price;	// 重载后小于号还是小于号的作用。
	}
};
#include <iostream>
#include <string>
#include <queue> 
using namespace std;
struct fruit {
	string name;
	int price;
	friend bool operator < (fruit f1, fruit f2) {
		return f1.price < f2.price;	//水果的价格高的为优先级高
	}
}f1, f2, f3;
int main(void){
    priority_queue<fruit> q;
    f1.name = "桃子";
    f1.price = 3; 
    f2.name = "苹果";
    f2.price = 4; 
    f3.name = "香蕉";
    f3.price = 1; 
    q.push(f1);
    q.push(f2);
    q.push(f3);
    cout << q.top().name << " " << q.top().price << endl;
    return 0;
}

同理,希如果望按水果的价格低的为优先级高,只需要把return中的小于号改为大于号。

#include <iostream>
#include <string>
#include <queue> 
using namespace std;
struct fruit {
	string name;
	int price;
	friend bool operator < (fruit f1, fruit f2) {
		return f1.price > f2.price;	//水果的价格低的为优先级高
	}
}f1, f2, f3;
int main(void){
    priority_queue<fruit> q;
    f1.name = "桃子";
    f1.price = 3; 
    f2.name = "苹果";
    f2.price = 4; 
    f3.name = "香蕉";
    f3.price = 1; 
    q.push(f1);
    q.push(f2);
    q.push(f3);
    cout << q.top().name << " " << q.top().price << endl;
    return 0;
}
记住:**优先队列的这个函数与sort中的函数效果是相反的!**
在排序中,return f1.price > f2.price;表示按价格从低到高,
而在优先队列中却是把价格低的放队首。
这是因为优先队列本身默认的规则就是优先级高的放队首,
因此把小于号重载为>的功能时只是把这个规则反了一下。

可以把sort中的cmp函数卸载结构体外面:

#include <iostream>
#include <string>
#include <queue> 
using namespace std;
struct fruit {
	string name;
	int price;
}f1, f2, f3;
struct cmp {
	bool operator () (fruit f1, fruit f2) {
		return f1.price > f2.price; //优先最小的,水果的价格低的为优先级高
	}
}; 
int main(){
    priority_queue<fruit, vector<fruit>, cmp> q;	//这种情况只能这样定义优先队列 
    f1.name = "桃子";
    f1.price = 3; 
    f2.name = "苹果";
    f2.price = 4; 
    f3.name = "香蕉";
    f3.price = 1; 
    q.push(f1);
    q.push(f2);
    q.push(f3);
    cout << q.top().name << " " << q.top().price << endl;
    return 0;
}

如果结构体内的数据庞大(例如出现字符串或数组) 建议使用引用来提升效率,此时比较类的参数中要加入const和&, 如下所示:

friend bool operator () (const fruit &f1, const fruit &f2) {
		return f1.price > f2.price;
	}
bool operator () (const fruit &f1, const fruit &f2) {
		return f1.price > f2.price;
	}

#include <iostream>
#include <set>

using namespace std;
class fruit {
public:
    string name;
    int price;
    fruit(string name,int price):name(name),price(price){}
};
struct doCompareFruit{
public:
    bool operator () (const fruit &f1, const fruit &f2) {
        return f1.price < f2.price;//价格低优先级高
    }
};

int main() {
    // 默认是 less  return 对象1 < 对象2;
    set<fruit, doCompareFruit> setVar;
    // 构建对象
    fruit f1 ("苹果", 10);
    fruit f2 ("香蕉", 20);
    fruit f3 ("榴莲", 30);

    // 把构建的对象 插入到 set 容器里面去
    setVar.insert(f1);
    setVar.insert(f2);
    setVar.insert(f3);
    
    for (set<fruit>::iterator it = setVar.begin(); it != setVar.end() ; it ++) {
        cout << it->name << " , " << it->price << endl;
    }
    return 0;
}

7.5 常见用处

 priority_queue可以解决一些贪心问题,也可以对DijKstra算法进行优化(因为优先队列的本质是堆)。

注意:使用top()函数前,要用empty()判断优先队列是否为空。

8. stack

栈,是STL实现的一个后进后出的容器。

8.1 定义

#include <iostream>
#include <stack>
using namespace std;

stack<typename> name;

8.2 stack内内容的访问

栈本身就是一种后进先出、先进后出的数据结构,在STL中的stack中只能通过top()来访问栈顶元素

#include <iostream>
#include <stack>
using namespace std;
int main(){
    stack<int> st;
    for(int i = 1; i <= 5; i++) {
        st.push(i);
    }
    cout << st.top() << endl;
    return 0;
}

8.3 常用函数

  • (1) push()
  • (2) top()
  • (3) pop()

弹出栈顶元素。

#include <iostream>
#include <stack>
using namespace std;
int main(){
    stack<int> st;
    for(int i = 1; i <= 5; i++) {
        st.push(i);
    }
    st.pop();
    cout << st.top() << endl;
    return 0;
}
  • (4) empty()
  • (5) size()

8.4 常见用处

stack用来模拟一些递归,防止程序对栈内存的限制而导致程序出错

9. pair

pair可以看作内部有两个元素的结构体,且这两个元素的类型是可以指定的,如:

struct pair {
	typename1 first;
	typename2 second;
};

9.1 定义

有两个参数,分别对应first和second的数据类型,他们可以是任意基本数据类型或容器。

pair<typename1, typename2> name;
如:
pair<string, int> p;

如果想在定义时初始化:
pair<string, int> p("haha", 5);

如果想在代码中临时构建一个pair,有如下两种方法:
pair<string, int>("haha", 5);
make_pair("haha", 5);

9.2 pair内内容的访问

pair中只有两个元素,分别是first和second,只需按正常结构体的方式访问即可

#include <iostream>
#include <utility>
using namespace std;
int main(){
    pair<string, int> p;
    p.first = "haha";
    p.second = 5;
    cout << p.first << " " << p.second << endl;
    p = make_pair("xixi", 3); //自带函数
    cout << p.first << " " << p.second << endl;
    p = pair<string, int>("wuwu", 555);
    cout << p.first << " " << p.second << endl;
    return 0;
}

9.3 常用函数

  • 比较操作数

两个pair类型数据可直接用==、!=、<等比较大小,规则是先比first,first相等时再比second。

#include <iostream>
#include <utility>
#include <string>
using namespace std;
int main(void){
	pair<int, int> p1(5, 55);
	pair<int, int> p2(5, 555);
	pair<int, int> p3(10, 5);
	if(p1 < p3)	cout << "p1 < p3" << endl;
	if(p1 <= p3)	cout << "p1 <= p3" << endl;
	if(p1 < p2)	cout << "p1 < p2" << endl;
    return 0;
}

9.4 常见用处

1. 用来代替二元结构体及其构造函数,可以节省编码时间。
2. 作为map的键值对来进行插入。

#include <iostream>
#include <map>
using namespace std;
int main(){
    map<string, int> mp;
    mp.insert(make_pair("heihei", 5));
    mp.insert(pair<string, int>("haha", 2));
    for(map<string, int>::iterator it = mp.begin(); it != mp.end(); it++) {
        cout << it->first << " " << it -> second << endl;
    }
    return 0;
}

10. list

List是stl实现的双向链表,与向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢

10.1 定义

#include <iostream>
#include <list> 
using namespace std;

list<int> list1;          //创建空list
list<int> list2(5);       //创建含有5个元素的list
list<int> list3(3,2);  //创建含有3个元素的list
list<int>  list4(lst2);    //使用lst2初始化lst4
list<int> list5(list2.begin(),list2.end());  //同lst4

10.2 List常用操作函数

    list<int> listVar;
    listVar.assign() //给list赋值
    listVar.back() //返回最后一个元素
    listVar.begin() //返回指向第一个元素的迭代器
    listVar.clear() //删除所有元素
    listVar.empty() //如果list是空的则返回true
    listVar.end() //返回末尾的迭代器
    listVar.erase()  // 删除一个元素
    listVar.front() //返回第一个元素
    listVar.get_allocator() //返回list的配置器
    listVar.insert() //插入一个元素到list中
    listVar.max_size() //返回list能容纳的最大元素数量
    listVar.merge() //合并两个list
    listVar.pop_back() //删除最后一个元素
    listVar.pop_front()// 删除第一个元素
    listVar.push_back() //在list的末尾添加一个元素
    listVar.push_front()// 在list的头部添加一个元素
    listVar.rbegin() //返回指向第一个元素的逆向迭代器
    listVar.remove() //从list删除元素
    listVar.remove_if() //按指定条件删除元素
    listVar.rend() //指向list末尾的逆向迭代器
    listVar.resize() //改变list的大小
    listVar.reverse()// 把list的元素倒转
    listVar.size() //返回list中的元素个数
    listVar.sort() //给list排序
    listVar.splice() //合并两个list
    listVar.swap() //交换两个list
    listVar.unique()// 删除list中重复的元素

10.3 List使用示例:

#include <iostream>
#include <list> 
using namespace std;

int main() {
    list<int> listVar;

    // 插入操作
    listVar.push_front(50); // 插入到前面   明确
    listVar.push_back(60); // 插入到后面
    listVar.insert(listVar.begin(), 70); // 插入到前面  灵活
    listVar.insert(listVar.end(), 80); // 插入到后面

    // 修改操作
    listVar.back() = 88;
    listVar.front() = 55;

    // 删除
    listVar.erase(listVar.begin()); // 删除最前面的 55
    listVar.erase(listVar.end()); // 删除最后面的 88

    // list 迭代器
    // 不用通过角标去访问,也不能修改   遍历
    for (list<int>::iterator it = listVar.begin(); it != listVar.end() ; it ++) {
        cout << *it << endl;
    }

    return 0;
}
// list的学习。 Java:ArrayList采用Object[]数组,   C++的list 内部:采用链表
#include <iostream>
#include <list>
#include <numeric>
#include <algorithm>

using namespace std;

typedef list<int> LISTINT;
typedef list<int> LISTCHAR;

int main() {
    //用LISTINT创建一个list对象
    LISTINT listOne;
    //声明i为迭代器
    LISTINT::iterator i;

    listOne.push_front(3);
    listOne.push_front(2);
    listOne.push_front(1);

    listOne.push_back(4);
    listOne.push_back(5);
    listOne.push_back(6);

    cout << "listOne.begin()--- listOne.end():" << endl;
    for (i = listOne.begin(); i != listOne.end(); ++i)
        cout << *i << " ";
    cout << endl;

    LISTINT::reverse_iterator ir;
    cout << "listOne.rbegin()---listOne.rend():" << endl;
    for (ir = listOne.rbegin(); ir != listOne.rend(); ir++) {
        cout << *ir << " ";
    }
    cout << endl;

    int result = accumulate(listOne.begin(), listOne.end(), 0);
    cout << "Sum=" << result << endl;
    cout << "------------------" << endl;

    //用LISTCHAR创建一个list对象
    LISTCHAR listTwo;
    //声明i为迭代器
    LISTCHAR::iterator j;

    listTwo.push_front('C');
    listTwo.push_front('B');
    listTwo.push_front('A');

    listTwo.push_back('D');
    listTwo.push_back('E');
    listTwo.push_back('F');

    cout << "listTwo.begin()---listTwo.end():" << endl;
    for (j = listTwo.begin(); j != listTwo.end(); ++j)
        cout << char(*j) << " ";
    cout << endl;

    j = max_element(listTwo.begin(), listTwo.end());
    cout << "The maximum element in listTwo is: " << char(*j) << endl;
    return 0;
}
#include <iostream>
#include <list>

using namespace std;
typedef list<int> INTLIST;

//从前向后显示list队列的全部元素
void put_list(INTLIST list, char *name) {
    INTLIST::iterator plist;
    cout << "The contents of " << name << " : ";
    for (plist = list.begin(); plist != list.end(); plist++)
        cout << *plist << " ";
    cout << endl;
}

//测试list容器的功能
int main() {
    //list1对象初始为空
    INTLIST list1;
    INTLIST list2(5, 1);
    INTLIST list3(list2.begin(), --list2.end());

    //声明一个名为i的双向迭代器
    INTLIST::iterator i;

    put_list(list1, "list1");
    put_list(list2, "list2");
    put_list(list3, "list3");

    list1.push_back(7);
    list1.push_back(8);
    cout << "list1.push_back(7) and list1.push_back(8):" << endl;
    put_list(list1, "list1");

    list1.push_front(6);
    list1.push_front(5);
    cout << "list1.push_front(6) and list1.push_front(5):" << endl;
    put_list(list1, "list1");

    list1.insert(++list1.begin(), 3, 9);
    cout << "list1.insert(list1.begin()+1,3,9):" << endl;
    put_list(list1, "list1");

    //测试引用类函数
    cout << "list1.front()=" << list1.front() << endl;
    cout << "list1.back()=" << list1.back() << endl;

    list1.pop_front();
    list1.pop_back();
    cout << "list1.pop_front() and list1.pop_back():" << endl;
    put_list(list1, "list1");

    list1.erase(++list1.begin());
    cout << "list1.erase(++list1.begin()):" << endl;
    put_list(list1, "list1");

    list2.assign(8, 1);
    cout << "list2.assign(8,1):" << endl;
    put_list(list2, "list2");

    cout << "list1.max_size(): " << list1.max_size() << endl;
    cout << "list1.size(): " << list1.size() << endl;
    cout << "list1.empty(): " << list1.empty() << endl;

    put_list(list1, "list1");
    put_list(list3, "list3");
    cout << "list1>list3: " << (list1 > list3) << endl;
    cout << "list1<list3: " << (list1 < list3) << endl;

    list1.sort();
    put_list(list1, "list1");

    list1.splice(++list1.begin(), list3);
    put_list(list1, "list1");
    put_list(list3, "list3");
    return 0;
}