C++ STL 标准模板库提供了丰富的容器和算法,这些模板可以灵活组合使用,以满足不同场景下的需求。本章内容将对前面学习的知识进行总结,并重点讲解如何灵活使用STL中的vector和map容器,以及如何结合不同的算法进行组合。

通过灵活组合使用这些容器和算法,能够满足不同场景下的需求,实现高效的数据处理和操作。STL的设计思想是将数据结构和算法进行分离,使得开发者能够更加专注于解决问题,提高了代码的可读性和可维护性。因此,掌握STL的使用技巧对于C++程序员来说是非常重要的。

11.1 字典拆分为列表

此代码创建了一个std::map容器,将一些测试数据插入到容器中,然后通过迭代器遍历该容器,并将keyvalue分别插入到vector容器中,形成两个列表。

最后,分别将这两个列表打印出来。该代码的核心功能是将一个std::map容器转换成两个vector容器,同时输出两个vector容器的内容,以此实现了std::map的分离操作。

  • 功能概述:将map字典拆分为vect_keyvect_value两个Vector列表
#include <iostream>
#include <string>
#include <map>
#include <vector>

using namespace std;

int main(int argc, char *argv[])
{
  std::map<long, std::string> map;

  // 插入测试数据
  map.insert(std::pair<long, std::string>(1001, "administrator"));
  map.insert(std::pair<long, std::string>(1002, "root"));
  map.insert(std::pair<long, std::string>(1003, "lyshark"));

  // 将字典拆分为列表
  std::vector<long> vect_key;
  std::vector<std::string> vect_value;

  for (std::map<long, std::string>::iterator it = map.begin(); it != map.end(); it++)
  {
    // 分别将key和value插入到列表
    vect_key.push_back(it->first);
    vect_value.push_back(it->second);
  }

  // 输出分割结果
  for (int x = 0; x < vect_key.size(); x++)
    std::cout << "Key: " << vect_key[x] << std::endl;

  for (int x = 0; x < vect_value.size(); x++)
    std::cout << "Value: " << vect_value[x] << std::endl;

  std::system("pause");
  return 0;
}

11.2 列表合并为字典

该代码创建了两个std::vector容器,分别包含一些测试数据,并将这两个容器的元素通过循环方式逐一插入到一个std::map容器中。最后,通过迭代器输出std::map容器中所有的键值对。

该代码的核心功能是将两个std::vector容器的元素分别对应地插入到一个std::map容器中,并将最终的结果进行打印输出。

  • 功能概述:将两个列表vect_keyvect_value通过循环合并为一个std::map字典
#include <iostream>
#include <string>
#include <map>
#include <vector>

using namespace std;

int main(int argc, char *argv[])
{
  // 定义列表并追加元素
  std::vector<long> vect_key;
  std::vector<std::string> vect_value;

  vect_key.push_back(1001);
  vect_key.push_back(1002);
  vect_key.push_back(1003);

  vect_value.push_back("administrator");
  vect_value.push_back("root");
  vect_value.push_back("lyshark");

  // 将列表依次插入到map容器
  std::map<long, std::string> map;

  // 先来判断两个列表是否一致
  if (vect_key.size() == vect_value.size())
  {
    // 循环插入到map容器
    for (int x = 0; x < vect_key.size(); x++)
    {
      map.insert(std::pair<long, std::string>(vect_key[x], vect_value[x]));
    }
  }

  // 输出插入后的map容器
  for (std::map<long, std::string>::iterator it = map.begin(); it != map.end(); it++)
  {
    std::cout << "Key: " << it->first << " | Value: " << it->second << std::endl;
  }

  std::system("pause");
  return 0;
}

11.3 根据字典键降序排序

该代码创建了一个std::map容器,其中std::stringkeyintvalue。通过指定greater<string>进行降序排列。该程序接着给容器对象添加多个键值对,其中包括使用insert()函数和数组索引语法添加键值对。

最后,该程序使用迭代器循环遍历map容器,将所有键值对按照key的降序依次输出。该代码的核心功能是创建一个带有某种关键字类型的std::map容器,并实现基本的添加数据和遍历数据的操作。

  • 提示:MAP字典第三个参数不指定则按照升序排列,如果指定了greater<string>则会按照降序排列
#include <iostream>
#include <functional>
#include <string>
#include <map>

using namespace std;

int main(int argc, char *argv[])
{
  // map第三个参数greater<string>其中的string指定的是map中key的值.
  std::map<std::string, int, greater<string>> map;
  std::map<std::string, int, greater<string>>::iterator iter;

  map["aa"] = 90;
  map["bbb"] = 95;
  map["cccc"] = 100;
  map.insert(map<string, int>::value_type("ddddd", 88));


  for (iter = map.begin(); iter != map.end(); iter++)
  {
    std::cout << "key: " << iter->first << " Value: " << iter->second << std::endl;
  }

  std::system("pause");
  return 0;
}

11.4 根据字典键长度排序

该段代码创建了一个std::map容器,其中keystd::string类型valueint类型。为实现按照key长度进行排序,需要额外定义一个key_string_cmp的结构体,该结构体要重载()运算符以实现比较大小的功能。

接着,程序添加多个字符串类型的键值对到map容器中,其中包括使用数组索引语法以及使用insert()函数添加键值对。最后,程序使用迭代器循环输出map容器的所有键值对,注意此时输出的键值对已经按照key长度排好序了。

该代码的核心功能是创建一个针对字符串类型keystd::map容器,并按照key长度进行排序,然后实现基本的添加数据和输出数据的功能。其中自定义排序需要我们定义key_string_cmp排序结构,并将其传递到map字典的第三个参数上即可。

#include <iostream>
#include <string>
#include <map>

using namespace std;

struct key_string_cmp
{
  bool operator() (const string& x, const string& y)
  {
    return x.length() < y.length();
  }
};

int main(int argc, char *argv[])
{
  // 针对字符串类型Key的排序
  std::map<std::string, int, key_string_cmp > string_map;
  std::map<std::string, int, key_string_cmp >::iterator string_iter;

  string_map["aaaa"] = 90;
  string_map["bb"] = 95;
  string_map["ccccc"] = 100;
  string_map["d"] = 24;

  for (string_iter = string_map.begin(); string_iter != string_map.end(); string_iter++)
  {
    std::cout << "key: " << string_iter->first << " Value: " << string_iter->second << std::endl;
  }

  std::system("pause");
  return 0;
}

11.5 根据字典值排序

该代码创建了一个std::map容器,其中keystd::string类型valueint类型。程序使用数组索引语法添加多个键值对。接着,该程序将map容器中的数据取出来,放入到vector容器中,实现了将std::map转换为std::vector的功能。

接下来,程序使用sort()函数对转换为vector结构的序列进行排序,此处使用的是value_cmp结构体对value进行排序。最后,该程序输出排序后的vector容器的内容,此处输出的是keyvalue,且是按照value 从小到大的顺序输出。

该代码的核心功能是将一个std::map容器转换为std::vector容器,并按照某种规则对该vector进行排序,以此实现对std::map中数据的排序功能。

#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <map>

using namespace std;

typedef pair<string, int> PAIR;

struct value_cmp
{
  bool operator() (const PAIR& P1, const PAIR& P2)
  {
    return P1.second < P2.second;
  }
};

int main(int argc, char *argv[])
{
  std::map<std::string, int> map;
  std::map<std::string, int>::iterator iter;

  map["admin"] = 90;
  map["root"] = 95;
  map["lyshark"] = 100;

  // 将map容器中的数据取出来,放入到Vector
  vector<PAIR>vect;
  for (iter = map.begin(); iter != map.end(); iter++)
  {
    vect.push_back(*iter);
  }

  // 对转换为Vector结构的序列进行排序,此处使用value_cmp()
  sort(vect.begin(), vect.end(), value_cmp());

  // 输出排序后的Vector结构
  for (int x = 0; x < vect.size(); x++)
  {
    std::cout << "输出Key: " << vect[x].first << std::endl;
    std::cout << "输出Value: " << vect[x].second << std::endl;
  }

  std::system("pause");
  return 0;
}

11.6 根据字典键返回值

该代码创建了一个std::map容器,其中keystd::string类型,valueint类型。程序使用数组索引语法添加多个键值对。

该程序实现了两种查找功能:

  • 非函数版寻找:使用find()函数根据key查找相应的value,如果查找到就输出值
  • 在函数版寻找:使用get_value()函数根据key查找相应的value,并返回该值,如果找不到则返回0

最后,该程序输出找到的value。需要注意的是,两种方式都可以寻找相应的值。

该代码的核心功能是实现根据keystd::map容器中查找对应的值并输出结果。其中,采用了两种查找方式,一种是使用map自带的find()函数,另一种是通过定义一个函数实现的查找功能。

#include <iostream>
#include <functional>
#include <string>
#include <map>

using namespace std;

// 根据Key寻找Value并返回
int get_value(std::map<std::string,int> ptr, std::string key)
{
  std::map<std::string, int>::iterator iter;

  iter = ptr.find(key);
  if (iter != ptr.end())
  {
    // std::cout << iter->second << std::endl;
    return iter->second;
  }
  return 0;
}

int main(int argc, char *argv[])
{
  std::map<std::string, int> map;
  std::map<std::string, int>::iterator iter;

  map["admin"] = 90;
  map["root"] = 95;
  map["lyshark"] = 100;

  // 非函数版寻找
  iter = map.find("lyshark");
  if (iter != map.end())
  {
    std::cout << "找到数值: " << iter->second << std::endl;
  }

  // 函数版寻找
  int ref_value = get_value(map, "root");
  std::cout << "找到数值: " << ref_value << std::endl;

  std::system("pause");
  return 0;
}

11.7 根据字典值寻找键

该段代码创建了一个std::map容器,其中keyint类型valuestd::string类型。程序使用insert()函数向map容器中添加了多个元素。

该程序实现了两种查找功能:未封装的查找与封装函数版查找。在未封装的查找中,使用find_if()函数根据value完成查找;在封装函数版查找中,通过定义一个类map_value_finder实现find_if()函数。

最后,该程序输出找到的keyvalue。需要注意的是,两种方式都可以寻找相应的keyvalue

该代码的核心功能是实现根据valuestd::map容器中查找相应的keyvalue,并输出结果。其中,采用了两种查找方式,一种是使用find_if()函数,另一种是通过定义一个类封装实现的查找功能。

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>

using namespace std;

// 定义查找方法
class map_value_finder
{
public:
  map_value_finder(const std::string &cmp_string) :m_s_cmp_string(cmp_string){}

  bool operator ()(const std::map<int, std::string>::value_type &pair)
  {
    return pair.second == m_s_cmp_string;
  }
private:
  const std::string &m_s_cmp_string;
};

// 函数版根据Map的Value寻找key
std::pair < int, std::string > get_item(std::map<int,std::string> ptr, std::string value)
{
  std::map < int, std::string >::iterator it = ptr.end();

  // 根据传入的value寻找字典匹配数据
  it = std::find_if(ptr.begin(), ptr.end(), map_value_finder(value));

  // 无论是否找到都需要返回一个对组
  std::pair < int, std::string > ref_pair;
  if (it == ptr.end())
  {
    // 如果没找到直接返回空的对组
    ref_pair = std::make_pair(0, "None");
    return ref_pair;
  }
  else
  {
    ref_pair = std::make_pair(it->first, it->second);
    return ref_pair;
  }
}

int main(int argc,char * argv[])
{
  std::map<int, std::string> map;

  map.insert(std::make_pair(10, "china"));
  map.insert(std::make_pair(20, "usa"));
  map.insert(std::make_pair(30, "english"));
  map.insert(std::make_pair(40, "hongkong"));

  // 未封装的查找
  std::map<int, std::string>::iterator it = map.end();
  it = std::find_if(map.begin(), map.end(), map_value_finder("usa"));

  if (it == map.end())
  {
    std::cout << "没找到.." << std::endl;
  }
  else
  {
    std::cout << "找到的Key: " << it->first << " 找到的Value: " << it->second.c_str() << std::endl;
  }

  // 封装函数版查找
  std::pair<int, std::string> ref = get_item(map, "english");
  std::cout << "找到的Key: " << ref.first << " 找到的Value: " << ref.second << std::endl;

  std::system("pause");
  return 0;
}

11.8 寻找列表中相同元素

这段代码演示了两种查找算法find()find_first_of(),实现了寻找两个列表中第一次出现在第二个容器中的元素。

  • 第一种查找算法,使用find()函数在vector容器中查找特定元素,如果查找成功,则输出元素在容器中的位置(下标)。注意,该函数仅查找序列中的第一个符合条件的元素。
  • 第二种查找算法,使用find_first_of()函数在两个vector容器之间查找相同元素,如果查找成功,则输出该元素及其位置。注意,该函数查找的是两个序列中第一个相同的元素,而不是整个序列中相同的元素。

此外,该程序还定义了一个函数test_find_if(),用于在vector容器中查找满足特定条件的元素,如果查找成功,则输出该元素及其位置(下标)。

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>

using namespace std;

// 使用自定义函数
bool MyFunction(int x)
{
  if (x >= 9)
    return 1;
  else
    return 0;
}

// 遍历时增加过滤条件
void test_find_if(vector<int> ptr)
{
  vector<int>::iterator iter;
  iter = find_if(ptr.begin(), ptr.end(), MyFunction);

  if (iter != ptr.end())
  {
    cout << "满足条件的数: " << *iter << " 下标: " << iter - ptr.begin() << endl;
  }
}

// 查找两个数组相同部分
void test_find_first_of(std::vector<int> VectA,std::vector<int> VectB)
{
  vector<int>::iterator iter;
  iter = find_first_of(VectA.begin(), VectA.end(), VectB.begin(), VectB.end());
  if (iter != VectA.end() || iter != VectB.end())
  {
    cout << "第一次出现在第二个容器中的元素为: " << *iter << "  下标: " << iter - VectA.begin() << endl;
  }
  else
  {
    cout << "两个容器没有相同元素" << endl;
  }
}

int main(int argc,char * argv[])
{
  // 通过元素值,寻找下标
  std::vector<int> vect = { 1, 5, 6, 7, 8, 9, 0, 3, 2, 1 };
  std::vector<int>::iterator iter;

  iter = find(vect.begin(), vect.end(), 7);
  if (iter != vect.end())
  {
    std::cout << "找到元素下标: " << distance(vect.begin(), iter) << std::endl;
  }
  test_find_if(vect);

  // 寻找两个列表中的相同元素
  std::vector<int> VectA = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  std::vector<int> VectB = { 5, 6, 7, 8, 9, 4, 32, 6, 8, 9 };
  test_find_first_of(VectA, VectB);

  std::system("pause");
  return 0;
}

11.9 查找列表中的交集

这段代码实现了一个函数get_vect_value_list(),可以查找两个vector容器中相同的元素,并将这些元素放入一个新的vector容器中并返回。在具体实现中,使用了STL中的find()函数来查找相同的元素,并通过push_back()函数将查找到的元素添加到新的vector容器中。

在主函数中,定义两个vector容器VectAVectB,并使用get_vect_value_list()函数获取两个vector中相同的元素,并将其赋值给item。最后使用for循环遍历返回两者的交集列表。

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>

using namespace std;

// 查询两个列表中相同的元素,并返回一个列表
std::vector<int> get_vect_value_list(std::vector<int> VectA, std::vector<int> VectB)
{
  std::vector<int> item = {};

  std::vector<int>::iterator iter;

  // 两个列表必须一致
  if (VectA.size() == VectB.size())
  {
    for (int x = 0; x < VectA.size(); x++)
    {
      iter = find(VectB.begin(), VectB.end(), VectA[x]);
      if (iter != VectB.end())
      {
        // 找到后加入到item
        item.push_back(*iter);
      }
    }
  }
  return item;
}

int main(int argc,char * argv[])
{
  std::vector<int> VectA = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  std::vector<int> VectB = { 5, 6, 7, 8, 9, 4, 32, 6, 8, 9 };

  // 寻找元素
  std::vector<int> item = get_vect_value_list(VectA, VectB);

  for (int x = 0; x < item.size(); x++)
  {
    std::cout << "A中元素与B中都存在的: " << item[x] << std::endl;
  }

  std::system("pause");
  return 0;
}

11.10 根据键设置字典值

在本程序中,定义了两个函数set_dict_value()get_dict_value(),分别用于设置和获取map容器中指定keyvalue。在具体实现中,使用STL中的find()函数来查找指定key的位置,然后通过修改该位置对应的value 的值来实现修改操作;另外,使用该函数还可以避免在添加元素时出现重复的键值对。

在主函数中,先使用insert()函数向map容器中添加若干键值对;然后使用set_dict_value()函数将key为1的值修改为1000;接着使用get_dict_value()函数获取key为3的值;最后使用for循环遍历map容器中的所有键值对,并输出键和值。

读者需要注意,map容器的键和值可以是任意类型,而且键必须是没有重复值的,因为map是依靠键来查找值的。

#include <iostream>
#include <vector>
#include <map>
#include <string>

using namespace std;

// 设置指定key中的value
bool set_dict_value(std::map<int, int>& ptr, int find_key, int set_value)
{
  std::map<int, int>::iterator iter;
  // find_key 寻找key
  iter = ptr.find(find_key);
  if (iter != ptr.end())
  {
    // 替换value
    iter->second = set_value;
    return true;
  }
  return false;
}

// 根据find_key获取到字典的value,并返回
int get_dict_value(std::map<int, int>& ptr, int find_key)
{
  std::map<int, int>::iterator iter;
  // find_key 寻找key
  iter = ptr.find(find_key);
  if (iter != ptr.end())
  {
    // 返回当前值
    return iter->second;
  }
  return false;
}

int main(int argc, char * argv[])
{
  std::map<int, int> map;

  // 增加记录
  map.insert(std::pair<int, int>(1, 100));
  map.insert(std::pair<int, int>(2, 200));
  map.insert(std::pair<int, int>(3, 300));
  map.insert(std::pair<int, int>(4, 400));

  // 将map中的key=1 的value的值设置为 1000
  bool ref = set_dict_value(map, 1, 1000);
  std::cout << "设置状态: " << ref << std::endl;

  // 获取特定key的value值
  int _value = get_dict_value(map, 3);
  std::cout << "获取数据: " << _value << std::endl;

  // 输出设置后的状态
  for (std::map<int, int>::iterator ptr = map.begin(); ptr != map.end(); ptr++)
  {
    std::cout << "Key: " << ptr->first << " Value: " << ptr->second << std::endl;
  }

  std::system("pause");
  return 0;
}

11.11 实现列表容器计数

这段代码实现了统计一个vector容器中各个元素出现次数的功能。在具体实现中,使用map容器来保存元素及其出现次数的对应关系。对于每个元素,先使用count()函数查找其在map容器中的出现次数,如果不是第一次出现,则从map容器中取出其出现次数后递增,再将修改后的次数更新回map容器;否则,将其次数设置为1。最后,使用for循环遍历map容器,并输出元素及其出现次数。

读者需要注意,这段代码中使用了STL中的operator[],该运算符在map容器中可以用来访问指定键的值,同时也可以用于添加新的键值对。另外,需要注意count()函数的返回值类型是size_t,因此不能和int类型的变量直接比较大小。

#include <iostream>
#include <vector>
#include <string>
#include <map>

using namespace std;

// 设置指定key中的value
bool set_dict_value(std::map<int, int>& ptr, int set_key, int set_value)
{
  ptr[set_key] = set_value;
  return true;
}

// 根据find_key获取到字典的value,并返回
int get_dict_value(std::map<int, int>& ptr, int find_key)
{
  std::map<int, int>::iterator iter;
  iter = ptr.find(find_key);
  if (iter != ptr.end())
  {
    return iter->second;
  }
  return false;
}

int main(int argc, char * argv[])
{
  std::map<int, int> map;
  std::vector<int> vect = { 54, 66, 78, 34, 44, 44, 56, 3, 4, 56, 7, 89, 7, 5, 34, 4, 56, 7, 8, 90, 0, 8, 6, 4, 3 };

  for (int x = 0; x < vect.size(); x++)
  {
    // 寻找map中是否存在列表中的特定元素
    int ref = map.count(vect[x]);
    if (ref != 0)
    {
      // 不是第一次则,先取出原值,递增后,在回写.
      int _value = get_dict_value(map, vect[x]);
      _value = _value + 1;
      set_dict_value(map, vect[x], _value);
    }
    else
    {
      // 如果是第一次找到,直接设置为1
      set_dict_value(map, vect[x], 1);
    }
  }

  // 输出计数器
  for (std::map<int, int>::iterator iter = map.begin(); iter != map.end(); iter++)
  {
    std::cout << "数字: " << iter->first << " --> 出现次数: " << iter->second << std::endl;
  }

  std::system("pause");
  return 0;
}

11.12 验证两个列表异同点

这段代码演示了如何比较两个vector容器之间的差异。先定义了两个函数,分别为find_vector_value()get_list_value_list()

find_vector_value() 函数用于检查某个元素是否存在于vector容器中。具体实现中,使用STL中的find()函数来查找指定元素的位置,如果该元素存在于容器中,则返回 true;否则返回 false。

get_list_value_list() 函数用于比较两个vector容器之间的差异。具体实现中,先判断两个容器的长度是否相等,如果不相等则直接返回false。否则,对于vectorA容器中的每个元素,都调用find_vector_value()函数查找其是否存在于vectorB容器中;如果存在,则将该元素添加到result_identical容器中,否则,将其添加到result_different容器中。最后,该函数返回true,表示执行成功。

在主函数中,先定义了两个vector容器xy,然后调用get_list_value_list()函数,将xy之间的差异分别存储在名为identicaldifferent的容器中。最后,使用for循环遍历这两个容器,并输出它们所包含的元素。

#include <iostream>
#include <vector>
#include <string>
#include <algorithm>

using namespace std;

// 寻找特定元素是否存在于列表中
bool find_vector_value(std::vector<int> ptr, int find_value)
{
  std::vector<int>::iterator iter;

  if (ptr.size() >= 0)
  {
    for (int x = 0; x < ptr.size(); x++)
    {
      iter = find(ptr.begin(), ptr.end(), find_value);
      if (iter != ptr.end())
      {
        return true;
      }
    }
  }
  return false;
}

// 传入两个列表,返回 result_identical = 相同 / result_different = 不同
bool get_list_value_list(std::vector<int> vect_a, std::vector<int> vect_b, std::vector<int>& result_identical, std::vector<int>& result_different)
{
  std::vector<int>::iterator iter;

  // 如果两个列表相同,则我们以第一个列表作为循环变量
  if (vect_a.size() == vect_b.size())
  {
    for (int x = 0; x < vect_a.size(); x++)
    {
      // 验证vect_b 里面是否存在vect_a中的特定元素
      bool ref = find_vector_value(vect_b, vect_a[x]);
      if (ref == true)
      {
        result_identical.push_back(vect_a[x]);
      }
      else if (ref != true)
      {
        result_different.push_back(vect_a[x]);
      }
    }
    return true;
  }
  return false;
}

int main(int argc,char * argv[])
{
  std::vector<int> x = { 23, 56, 55, 43, 7, 8, 9, 0, 5, 4, 6, 7, 8, 9, 4 };
  std::vector<int> y = { 23, 56, 55, 334, 7, 8, 9, 0, 5, 4, 6, 7, 8, 9, 4 };

  // identical 存放两者都有的 / different 存放两者都没有的
  std::vector<int> identical;
  std::vector<int> different;

  get_list_value_list(x, y, identical, different);

  for (int x = 0; x < identical.size(); x++)
  {
    std::cout << "x中存在的元素: " << identical[x] << std::endl;
  }

  for (int x = 0; x < different.size(); x++)
  {
    std::cout << "x中不存在的元素: " << different[x] << std::endl;
  }
  
  std::system("pause");
  return 0;
}

11.13 实现两个列表合并

这段代码实现了将两个vector容器中的元素进行合并的功能。具体实现中,使用extend_vector_list()函数来实现。

extend_vector_list() 函数用于合并两个vector容器中的元素。该函数有三个参数,分别为vect_x、vect_yignore。其中,vect_xvect_y分别表示要进行合并的两个vector容器;ignore 参数表示是否忽略重复元素,如果为 true,则在合并过程中会自动去重,否则会保留重复元素。

具体实现中,先将vect_x中的所有元素添加到item容器中,然后将vect_y中的所有元素依次逐个进行查找,根据ignore参数的不同处理方式,对于不存在于item容器中的元素,将其添加到item容器中。最后,该函数返回item容器,表示执行成功。

在主函数中,先定义了两个要合并的vector容器xy,然后调用extend_vector_list()函数进行合并。因为ignore参数设置为 true,所以在合并过程中会自动去除重复元素。最后使用for循环遍历合并后的vect容器,并输出它们所包含的元素。

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <algorithm>

using namespace std;

// 寻找特定元素是否存在于列表中
bool find_vector_value(std::vector<int> ptr, int find_value)
{
  std::vector<int>::iterator iter;

  if (ptr.size() >= 0)
  {
    for (int x = 0; x < ptr.size(); x++)
    {
      iter = find(ptr.begin(), ptr.end(), find_value);
      if (iter != ptr.end())
      {
        return true;
      }
    }
  }
  return false;
}

// 合并两个列表元素
std::vector<int> extend_vector_list(std::vector<int> &vect_x, std::vector<int> &vect_y, bool ignore = false)
{
  std::vector<int> item;

  // 循环现将vect_x 赋值给item
  for (int x = 0; x < vect_x.size(); x++)
  {
    item.push_back(vect_x[x]);
  }

  // 循环vect_y是否存在
  for (int x = 0; x < vect_y.size(); x++)
  {
    // 是否忽略重复元素
    if (ignore == true)
    {
      // 判断item里面是否存在vect_y[x]元素
      bool ref = find_vector_value(item, vect_y[x]);
      if (ref != true)
      {
        item.push_back(vect_y[x]);
      }
    }
    else
    {
      item.push_back(vect_y[x]);
    }
  }
  return item;
}

int main(int argc,char * argv[])
{
  std::vector<int> vect;

  std::vector<int> x = { 1, 2, 3, 4, 5 };
  std::vector<int> y = { 5, 6, 7, 8, 9, 10, 11};

  // 合并两个列表元素,第三个参数判断,是否忽略重复元素合并
  vect = extend_vector_list(x, y, true);
  for (int x = 0; x < vect.size(); x++)
  {
    std::cout << "合并后: " << vect[x] << std::endl;
  }
  std::system("pause");
  return 0;
}

11.14 字典与列表的嵌套

对于嵌套列表的实现,代码首先定义了一个vector容器vect,该容器中的每个元素都是另一个vector容器。通过push_back()函数,将两个内部vector容器的元素添加到外部的vect容器中。然后使用两层for循环遍历外部和内部的容器,并输出它们所包含的每一个子元素。

对于嵌套多个字典的实现,代码定义了一个vector容器vect,该容器中的每个元素都是一个map容器。map容器中的一个key对应一个vector容器。通过push_back()函数,将两个内部map容器的元素添加到外部的vect容器中。然后使用两层for循环遍历外部和内部的容器,并输出它们所包含的每一个子元素。

对于解析内部map容器中的元素,需要使用迭代器进行遍历,具体实现还将其中的vector容器解析出来,并输出其中的每一个元素。

#include <iostream>
#include <vector>
#include <map>
#include <string>

using namespace std;

// 实现列表中嵌套列表
// list[ ["192.168.1.1","root","1233"] , ["192.168.1.2","lyshark","123456"] ]
void list_nesting_list()
{
  std::vector<std::vector<std::string>> vect;

  std::vector<std::string> tmp;
  tmp.push_back("192.168.1.1");
  tmp.push_back("root");
  tmp.push_back("1233");
  vect.push_back(tmp);

  tmp.clear();
  tmp.push_back("192.168.1.2");
  tmp.push_back("lyshark");
  tmp.push_back("123456");
  vect.push_back(tmp);

  // 输出外层
  for (int x = 0; x < vect.size(); x++)
  {
    // 输出内层
    for (int y = 0; y < vect[x].size(); y++)
    {
      std::cout << vect[x][y] << std::endl;
    }
  }
}

// 实现列表中嵌套多个字典
// list[ {"Key": "192.168.1.1", "Value": [1,2,3,4,5] } , {"Key": "192.168.1.2", "Value" : [1,2,3] } ]
void list_nesting_dict()
{
  std::vector< std::map<std::string, std::vector<int> > > vect;

  // 填充map内部的vector容器
  std::vector<int> internal;
  std::string internal_string;
  std::map<std::string, std::vector<int> > map;

  // 插入第1条数据
  internal_string = "192.168.1.1";
  internal = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
  map[internal_string] = internal;
  vect.push_back(map);

  // 插入后记得清理无用数据
  internal.clear();
  internal_string.clear();
  map.clear();

  // 插入第2条数据
  internal_string = "192.168.1.2";
  internal = { 1, 2, 3, 4, 5, 6 };
  map[internal_string] = internal;
  vect.push_back(map);

  // 输出外层vector数据: std::vector<...> vect;
  for (int x = 0; x < vect.size(); x++)
  {
    // 输出内层map数据: std::map<std::string, std::vector<int> >
    std::map<std::string, std::vector<int>>::iterator iter;
    for (iter = vect[x].begin(); iter != vect[x].end(); iter++)
    {
      std::cout << "Key: " << iter->first << std::endl;

      // 解析并输出内部数据: std::vector<int>
      std::vector<int> vector_ptr = iter->second;
      for (int y = 0; y < vector_ptr.size(); y++)
      {
        std::cout << vector_ptr[y] << std::endl;
      }
    }
  }
}

int main(int argc,char * argv[])
{
  list_nesting_dict();
  list_nesting_list();
  std::system("pause");
  return 0;
}

11.15 可存储多类型容器

这段代码使用了boost库的variant类型,实现了一个可变类型容器,用来存储两种不同类型,代码首先定义了一个名为varvariant类型数组,其大小为 3,可以容纳两种不同类型的vector容器。同时,它将一个std::vectorstd::stringstd::vector<int>赋值给var数组的第0个和第1个元素。

随后,代码使用循环遍历该数组,通过boost库的get函数获取存储在var数组中的元素。如果顺利获取到该元素,则可以进行类型判断,从中提取出对应的vector容器。

最后,代码使用循环遍历表示vector容器内部的元素,并输出每一个元素的值。

#include <iostream>
#include <string>
#include <vector>
#include <boost/variant.hpp>

using namespace std;
using namespace boost;

int main(int argc, char const *argv[])
{
  // 定义可容纳 string,int 等类型的容器
  boost::variant < std::vector<std::string>, std::vector<int>> var[3];

  // 赋值第一个字符串数据集
  std::vector<std::string> string_ptr;
  string_ptr.push_back("string1");
  string_ptr.push_back("strin2");
  string_ptr.push_back("strin3");
  var[0] = string_ptr;

  // 赋值第二个字符串数据集
  std::vector<int> int_ptr;
  int_ptr.push_back(1);
  int_ptr.push_back(2);
  int_ptr.push_back(3);
  var[1] = int_ptr;

  for (int x = 0; x < 2; x++)
  {
    if (var[x].type() == typeid(std::vector<std::string>))
    {
      // 输出第一个字符串数据集
      std::vector<std::string> string_vect;
      string_vect = boost::get< std::vector<std::string> >(var[0]);
      for (int x = 0; x < string_vect.size(); x++)
      {
        std::cout << "字符串结构: " << string_vect[x] << std::endl;
      }
    }
    else if (var[x].type() == typeid(std::vector<int>))
    {
      // 输出第二个整数数据集
      std::vector<int> int_vect;
      int_vect = boost::get< std::vector<int> >(var[1]);
      for (int x = 0; x < int_vect.size(); x++)
      {
        std::cout << "整数结构: " << int_vect[x] << std::endl;
      }
    }
  }

  std::system("pause");
  return 0;
}

11.16 列表随机弹出元素

这段代码通过使用标准库和boost库提供的随机数生成器方法,实现了从一个字符串vector容器中随机弹出一个元素的功能。

函数get_random_value使用标准库的srand()函数配合std::rand()函数实现随机生成整数。该随机生成器并不是真正的随机数生成器,而是伪随机数生成器。函数接受一个vector容器,并返回其中随机抽取的一个元素。

函数get_boost_random_value使用boost库提供的mt19937uniform_int<>类型的随机生成器实现真随机数的生成。该函数的实现相对更加健壮,并且需要的代码量也更多。此函数也接受一个vector容器,并返回其中随机抽取的一个元素。

main()函数中,将标准库和boost版本的随机函数各循环执行了10次,并在每轮循环中输出从vector容器中随机取出的元素。需要注意的是,在标准库实现弹出随机数的函数中,随机数生成器需要使用当前的系统时间作为种子,因此可产生结果不同的随机数序列。而在boost实现的随机弹出元素的函数中,每次的随机数序列是非常随机且预测不可能的。

关于选择哪种生成随机数的方法,需根据实际情况进行选择。若仅是生成一些简单的随机数,则标准库的伪随机数生成器就足够使用;若需要生成复杂和预测性极低的应用程序,则需使用boost库的真随机数生成器。

#include <iostream>
#include <stdlib.h>
#include <string>
#include <vector>
#include <time.h>
#include <boost/random.hpp>
#include <boost/random/random_device.hpp>

using namespace std;
using namespace boost;

// 标准库实现随机弹出元素
std::string get_random_value(std::vector<std::string> &ptr)
{
  srand(unsigned(time(0)));
  int count = ptr.size();
  std::string ref = ptr.at(std::rand() % count);
  return ref;
}

// boost实现的随机取出元素
std::string get_boost_random_value(std::vector<std::string> &ptr)
{
  boost::mt19937 gen;
  boost::uniform_int<>distribut(1, 10);
  boost::variate_generator<mt19937 &, uniform_int<>> die(gen, distribut);

  int count = ptr.size();
  std::string ref = ptr.at(std::rand() % count);
  return ref;
}

int main(int argc, char * argv[])
{
  std::vector<std::string> vect;

  vect.push_back("admin");
  vect.push_back("lyshark");
  vect.push_back("location");
  vect.push_back("root");

  // 标准库实现弹出随机数
  for (int x = 0; x < 10; x++)
  {
    std::string ref = get_random_value(vect);
    std::cout << "标准库随机元素: " << ref << std::endl;
  }

  // boost 实现弹出随机数
  for (int x = 0; x < 10; x++)
  {
    std::string ref = get_boost_random_value(vect);
    std::cout << "boost 随机元素: " << ref << std::endl;
  }

  std::system("pause");
  return 0;
}

11.17 实现队列参数计算

这段代码定义了一个MyData类,包括两个数据成员uuiduname,以及一个get()函数。该函数将传入的两个整数参数与uuid进行加法计算,并返回计算结果。

main()函数中,定义了一个std::queue<MyData>类型的队列对象queue_ptr,插入了5MyData类型的元素。接下来,在一个while循环中,将队列顶部的元素取出,并根据MyData对象的get()函数计算它的数值加和。将计算结果与名字信息组成std::pair<std::string, int> 按顺序添加到一个vector容器check_sum_list中。

最后,循环遍历check_sum_list向控制台输出每个std::pair<std::string, int>元素的内容。

#include <iostream>
#include <string>
#include <vector>
#include <queue>

using namespace std;

class MyData
{
public:
  int uuid;
  std::string uname;

  MyData(int x, std::string y)
  {
    uuid = x;
    uname = y;
  }

  // 实现参数计算
  int get(int value_a, int value_b)
  {
    return uuid + value_a + value_b;
  }
};

int main(int argc, char *argv[])
{
  std::vector<std::pair<std::string, int>> check_sum_list;
  std::queue<MyData> queue_ptr;

  // 插入数据
  queue_ptr.push(MyData(1001, "admin"));
  queue_ptr.push(MyData(1002, "lyshark"));
  queue_ptr.push(MyData(1003, "root"));
  queue_ptr.push(MyData(1004, "zhangsan"));
  queue_ptr.push(MyData(1005, "wangwu"));

  // 判断不为空
  while (!queue_ptr.empty())
  {
    std::pair<std::string, int> temp;

    // 取出队列头部元素
    MyData ptr = queue_ptr.front();
    int ref = ptr.get(100, 200);

    // std::cout << "名字: " << ref << "计算后: " << ref << std::endl;
    temp.first = ptr.uname;
    temp.second = ref;

    // 加入到vector容器
    check_sum_list.push_back(temp);
    queue_ptr.pop();
  }

  // 输出计算后的结果
  for (int x = 0; x <= check_sum_list.size(); x++)
  {
    std::cout << check_sum_list[x].first << check_sum_list[x].second << std::endl;
  }

  std::system("pause");
  return 0;
}

11.18 查找最大值/最小值

这段代码演示了如何使用Boost库的minmax_element算法,在一个vector容器中找到最大值和最小值,并找到最小值对应的条目。

find_list() 函数演示了如何在一个整数容器中找到最大值和最小值,以及如何查找第一个最小值和最后一个最小值的下标。

find_dict_minmax_element() 函数演示了如何在一个std::pair<int, std::string>容器中找到最小值和最大值,并返回最小值对应的std::pair<int, std::string>条目。

需要时,可以在比较函数中指定自定义的元素排序方式。如果在重载的比较函数中返回的是 bool 值,那么此函数找到的是容器中的单个元素,而不是元素的下标。如果返回的是迭代器,那么这个函数找到的则是对应下标位置的元素。

#include <iostream>
#include <string>
#include <vector>
#include <boost/algorithm/minmax_element.hpp>

using namespace std;

// 寻找最大值与最小值
void find_list()
{
  std::vector<int> vec = { 1, 4, 3, 2, 5, 6, 6, 6, 7, 8, 1, 4 };
  auto x = boost::minmax_element(vec.begin(), vec.end());

  cout << "最小值: " << *x.first << endl;
  cout << "最大值: " << *x.second << endl;

  decltype(vec.begin()) pos;
  pos = boost::first_min_element(vec.begin(), vec.end());
  cout << "第一个最小值: " << *pos << " 数组中位置: " << pos - vec.begin() << endl;

  pos = boost::last_min_element(vec.begin(), vec.end());
  cout << "最后一个最小值: " << *pos << " 数组中位置: " << pos - vec.begin() << endl;
}

// 寻找对组中的最大值与最小值,并返回对组
std::pair<int,std::string> find_dict_minmax_element(std::vector<std::pair<int,std::string>> ptr)
{
  // 将数据集下标放入vect_ptr容器
  std::vector<int> vect_ptr;
  for (int x = 0; x < ptr.size(); x++)
  {
    vect_ptr.push_back(x);
  }
  // 寻找最最小值,返回的是下标号
  auto x = boost::minmax_element(vect_ptr.begin(), vect_ptr.end());

  // *x.second = 返回最小值 / *x.first = 返回最大值
  std::pair<int, std::string> ref = ptr.at(*x.first);
  return ref;
}

int main(int argc, char *argv[])
{
  std::vector<std::pair<int, std::string>> ptr;

  // 增加记录
  ptr.push_back(std::pair < int, std::string >(98, "zhsngsan"));
  ptr.push_back(std::pair < int, std::string >(65, "lisi"));
  ptr.push_back(std::pair < int, std::string >(49, "wangwu"));

  // 寻找最大最小值
  std::pair<int, std::string> get = find_dict_minmax_element(ptr);
  std::cout << "姓名: " << get.second << std::endl;
  std::cout << "分数: " << get.first << std::endl;

  std::system("pause");
  return 0;
}

11.19 字典中嵌套结构体

这段代码演示了如何将自定义结构存储在map容器中,并对这些结构进行迭代遍历和访问。MyStruct定义了一个自定义的结构类型,包括两个整数成员变量xy,以及CheckSum()函数,该函数计算xy的和并返回结果。

main函数中,三个MyStruct类型的结构对象struct_ptr_a、struct_ptr_bstruct_ptr_c分别设置了不同的xy值,然后将它们插入到map容器中,每个结构对象的唯一键值std::pair<int, MyStruct>(1, struct_ptr_a)std::pair<int, MyStruct>(2, struct_ptr_b)std::pair<int, MyStruct>(3, struct_ptr_c)用于在map容器中存储对应结构。

接下来使用for循环迭代遍历结构体,并使用迭代器it访问map容器中的值。使用it->first访问结构的键值,使用it->second.xit->second.y访问结构的xy成员变量,使用it->second.CheckSum()访问结构的CheckSum()函数的返回值。在控制台输出取出结构元素的值和计算结果。

#include <iostream>
#include <string>
#include <map>

using namespace std;

// 自定义结构
typedef struct
{
  int x;
  int y;

  int CheckSum()
  {
    return x + y;
  }
}MyStruct;

typedef std::map<int, MyStruct> struct_map;

int main(int argc, char* argv[])
{
  struct_map map;
  MyStruct struct_ptr_a, struct_ptr_b, struct_ptr_c;

  struct_ptr_a.x = 100;
  struct_ptr_a.y = 200;

  struct_ptr_b.x = 10;
  struct_ptr_b.y = 20;

  struct_ptr_c.x = 12;
  struct_ptr_c.y = 30;

  // 将结构插入到map容器
  map.insert(std::pair<int, MyStruct>(1, struct_ptr_a));
  map.insert(std::pair<int, MyStruct>(2, struct_ptr_b));
  map.insert(std::pair<int, MyStruct>(3, struct_ptr_c));

  // 输出结构中的数据
  for (struct_map::iterator it = map.begin(); it != map.end(); it++)
  {
    std::cout << "Key: " << it->first << " Value X: " << it->second.x << std::endl;
    std::cout << "函数返回值: " << it->second.CheckSum() << std::endl;
  }

  std::system("pause");
  return 0;
}
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐