进阶C++

编程入门 行业动态 更新时间:2024-10-25 12:18:28

<a href=https://www.elefans.com/category/jswz/34/1769503.html style=进阶C++"/>

进阶C++

目录

一、关联式容器

二、键值对

三、树形结构的关联式容器

set/ multiset 容器

set基本概念

set构造和赋值

set大小和交换

set插入和删除

set查找和统计

set和multiset区别

set / multiset总结

pair对组创建

set容器排序

内置类型指定排序规则

自定义数据类型指定排序规则

map/ multimap容器

map基本概念

map构造和赋值

map大小和交换

map插入和删除

map查找和统计

map容器排序

map / multimap总结

OJ练习

set的算法常用方式

 两个数组的交集

set的算法常用方式

字符串中的第一个唯一字符

只出现一次的数字 II


一、关联式容器

在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、

forward_list(C++11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面存储的是元素本身。那什么是关联式容器?它与序列式容器有什么区别?

关联式容器也是用来存储数据的,与序列式容器不同的是,其里面存储的是<key, value>结构的键值对,在数据检索时比序列式容器效率更高

二、键值对

用来表示具有一一对应关系的一种结构,该结构中一般只包含两个成员变量key和value,key代表键值,value表示与key对应的信息

SGI-STL中关于键值对的定义:

template <class T1, class T2>
struct pair
{typedef T1 first_type;typedef T2 second_type;T1 first;T2 second;pair() : first(T1()), second(T2()){}pair(const T1& a, const T2& b) : first(a), second(b){}
};

三、树形结构的关联式容器

根据应用场景的不桶,STL总共实现了两种不同结构的管理式容器:树型结构与哈希结构。树型结 构的关联式容器主要有四种:map、set、multimap、multiset。这四种容器的共同点是:使用平衡搜索树(即红黑树)作为其底层结果,容器中的元素是一个有序的序列。下面一依次介绍每一个容器。

set/ multiset 容器

set文档介绍链接:set - C++ Reference

set基本概念

简介:

  • 所有元素都会在插入时自动被排序

本质:

  • set/multiset属于关联式容器,底层结构是用二叉树实现。

set和multiset区别

  • set不允许容器中有重复的元素
  • multiset允许容器中有重复的元素

set构造和赋值

功能描述:创建set容器以及赋值

构造:

  • set<T> st; //默认构造函数:
  • set(const set &st); //拷贝构造函数

赋值:

  • set& operator=(const set &st); //重载等号操作符
#include<iostream>
#include<string> 
using namespace std;
#include <set>void printSet(set<int> & s)
{for (set<int>::iterator it = s.begin(); it != s.end(); it++){cout << *it << " ";}cout << endl;
}//构造和赋值
void test01()
{set<int> s1;s1.insert(10);s1.insert(30);s1.insert(20);s1.insert(40);printSet(s1);//拷贝构造set<int>s2(s1);printSet(s2);//赋值set<int>s3;s3 = s2;printSet(s3);
}int main() {test01();system("pause");return 0;
}

输出:

10 20 30 40
10 20 30 40
10 20 30 40

总结:

  • set容器插入数据时用insert
  • set容器插入数据的数据会自动排序

set大小和交换

功能描述:

  • 统计set容器大小以及交换set容器

函数原型:

  • size(); //返回容器中元素的数目
  • empty(); //判断容器是否为空
  • swap(st); //交换两个集合容器

示例:

#include<iostream>
#include<string> 
using namespace std;
#include <set>void printSet(set<int> & s)
{for (set<int>::iterator it = s.begin(); it != s.end(); it++){cout << *it << " ";}cout << endl;
}//大小
void test01()
{set<int> s1;s1.insert(10);s1.insert(30);s1.insert(20);s1.insert(40);if (s1.empty()){cout << "s1为空" << endl;}else{cout << "s1不为空" << endl;cout << "s1的大小为: " << s1.size() << endl;}}//交换
void test02()
{set<int> s1;s1.insert(10);s1.insert(30);s1.insert(20);s1.insert(40);set<int> s2;s2.insert(100);s2.insert(300);s2.insert(200);s2.insert(400);cout << "交换前" << endl;printSet(s1);printSet(s2);cout << endl;cout << "交换后" << endl;s1.swap(s2);printSet(s1);printSet(s2);
}int main() {test01();test02();return 0;
}

输出:

s1不为空
s1的大小为: 4
交换前
10 20 30 40
100 200 300 400

交换后
100 200 300 400
10 20 30 40

set插入和删除

功能描述:

  • set容器进行插入数据和删除数据

函数原型:

  • insert(elem); //在容器中插入元素。
  • clear(); //清除所有元素
  • erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。
  • erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
  • erase(elem); //删除容器中值为elem的元素。
#include<iostream>
#include<string> 
using namespace std;
#include <set>void printSet(set<int> & s)
{for (set<int>::iterator it = s.begin(); it != s.end(); it++){cout << *it << " ";}cout << endl;
}//插入和删除
void test01()
{set<int> s1;//插入s1.insert(10);s1.insert(30);s1.insert(20);s1.insert(40);printSet(s1);//删除s1.erase(s1.begin());printSet(s1);s1.erase(30);printSet(s1);//清空//s1.erase(s1.begin(), s1.end());s1.clear();printSet(s1);
}int main() {test01();system("pause");return 0;
}

10 20 30 40
20 30 40
20 40
 

set查找和统计

功能描述:

  • 对set容器进行查找数据以及统计数据

函数原型:

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
  • count(key); //统计key的元素个数
#include<iostream>
#include<string> 
using namespace std;
#include <set>//查找和统计
void test01()
{set<int> s1;//插入s1.insert(10);s1.insert(30);s1.insert(20);s1.insert(40);//查找set<int>::iterator pos = s1.find(30);if (pos != s1.end()){cout << "找到了元素 : " << *pos << endl;}else{cout << "未找到元素" << endl;}//统计int num = s1.count(30);cout << "num = " << num << endl;
}int main() {test01();system("pause");return 0;
}

找到了元素 : 30
num = 1

set和multiset区别

学习目标:

  • 掌握set和multiset的区别

区别:

  • set不可以插入重复数据,而multiset可以
  • set插入数据的同时会返回插入结果,表示插入是否成功
  • multiset不会检测数据,因此可以插入重复数据
#include<iostream>
#include<string> 
using namespace std;
#include <set>//set和multiset区别
void test01()
{set<int> s;pair<set<int>::iterator, bool>  ret = s.insert(10);if (ret.second) {cout << "第一次插入成功!" << endl;}else {cout << "第一次插入失败!" << endl;}ret = s.insert(10);if (ret.second) {cout << "第二次插入成功!" << endl;}else {cout << "第二次插入失败!" << endl;}//multisetmultiset<int> ms;ms.insert(10);ms.insert(10);for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {test01();system("pause");return 0;
}

输出:

第一次插入成功!
第二次插入失败!
10 10

总结:

  • 如果不允许插入重复数据可以利用set
  • 如果需要插入重复数据利用multiset

set / multiset总结

1. set是按照一定次序存储元素的容器

2. 在set中,元素的value也标识它(value就是key,类型为T),并且每个value必须是唯一的。

set中的元素不能在容器中修改(元素总是const),但是可以从容器中插入或删除它们。

3. 在内部,set中的元素总是按照其内部比较对象(类型比较)所指示的特定严格弱排序准则进行排序。

4. set容器通过key访问单个元素的速度通常比unordered_set容器慢,但它们允许根据顺序对

子集进行直接迭代。

5. set在底层是用二叉搜索树(红黑树)实现的。

注意:

1. 与map/multimap不同,map/multimap中存储的是真正的键值对<key, value>,set中只放

value,但在底层实际存放的是由<value, value>构成的键值对

2. set中插入元素时,只需要插入value即可,不需要构造键值对。

3. set中的元素不可以重复(因此可以使用set进行去重)。

4. 使用set的迭代器遍历set中的元素,可以得到有序序列

5. set中的元素默认按照小于来比较

6. set中查找某个元素,时间复杂度为:log2 N

7. set中的元素不允许修改(为什么?)

8. set中的底层使用二叉搜索树(红黑树)来实现

pair对组创建

功能描述:

  • 成对出现的数据,利用对组可以返回两个数据

两种创建方式:

  • pair<type, type> p ( value1, value2 );
  • pair<type, type> p = make_pair( value1, value2 );
#include<iostream>
#include<string> 
using namespace std;
//对组创建
void test01()
{pair<string, int> p(string("Tom"), 20);cout << "姓名: " <<  p.first << " 年龄: " << p.second << endl;pair<string, int> p2 = make_pair("Jerry", 10);cout << "姓名: " << p2.first << " 年龄: " << p2.second << endl;
}int main() {test01();system("pause");return 0;
}

输出:

姓名: Tom 年龄: 20
姓名: Jerry 年龄: 10

set容器排序

内置类型指定排序规则

改变排序顺序核心 

class MyCompare 
{
public:bool operator()(int v1, int v2) {return v1 > v2;}
};
#include<iostream>
#include<string> 
using namespace std;
#include <set>class MyCompare 
{
public:bool operator()(int v1, int v2) {return v1 > v2;}
};
void test01() 
{    set<int> s1;s1.insert(10);s1.insert(40);s1.insert(20);s1.insert(30);s1.insert(50);//默认从小到大for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {cout << *it << " ";}cout << endl;//指定排序规则set<int,MyCompare> s2;s2.insert(10);s2.insert(40);s2.insert(20);s2.insert(30);s2.insert(50);for (set<int, MyCompare>::iterator it = s2.begin(); it != s2.end(); it++) {cout << *it << " ";}cout << endl;
}int main() {test01();system("pause");return 0;
}

输出:

10 20 30 40 50
50 40 30 20 10

利用仿函数可以指定set容器的排序规则

自定义数据类型指定排序规则

#include<iostream>
#include<string> 
using namespace std;
#include <set>class Person
{
public:Person(string name, int age){this->m_Name = name;this->m_Age = age;}string m_Name;int m_Age;};
class comparePerson
{
public:bool operator()(const Person& p1, const Person &p2){//按照年龄进行排序  降序return p1.m_Age > p2.m_Age;}
};void test01()
{set<Person, comparePerson> s;Person p1("刘备", 23);Person p2("关羽", 27);Person p3("张飞", 25);Person p4("赵云", 21);s.insert(p1);s.insert(p2);s.insert(p3);s.insert(p4);for (set<Person, comparePerson>::iterator it = s.begin(); it != s.end(); it++){cout << "姓名: " << it->m_Name << " 年龄: " << it->m_Age << endl;}
}
int main() {test01();system("pause");return 0;
}

输出:

姓名: 关羽 年龄: 27
姓名: 张飞 年龄: 25
姓名: 刘备 年龄: 23
姓名: 赵云 年龄: 21

对于自定义数据类型,set必须指定排序规则才可以插入数据

map/ multimap容器

map的文档简介链接:map - C++ Reference

map基本概念

简介:

  • map中所有元素都是pair
  • pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
  • 所有元素都会根据元素的键值自动排序

本质:

  • map/multimap属于关联式容器,底层结构是用二叉树实现。

优点:

  • 可以根据key值快速找到value值

map和multimap区别

  • map不允许容器中有重复key值元素
  • multimap允许容器中有重复key值元素

map构造和赋值

功能描述:

  • 对map容器进行构造和赋值操作

函数原型:

构造:

  • map<T1, T2> mp; //map默认构造函数:
  • map(const map &mp); //拷贝构造函数

赋值:

  • map& operator=(const map &mp); //重载等号操作符

示例:

#include<iostream>
#include<string> 
using namespace std;
#include <map>void printMap(map<int,int>&m)
{for (map<int, int>::iterator it = m.begin(); it != m.end(); it++){cout << "key = " << it->first << " value = " << it->second << endl;}cout << endl;
}void test01()
{map<int,int>m; //默认构造m.insert(pair<int, int>(1, 10));m.insert(pair<int, int>(2, 20));m.insert(pair<int, int>(3, 30));printMap(m);map<int, int>m2(m); //拷贝构造printMap(m2);map<int, int>m3;m3 = m2; //赋值printMap(m3);
}int main() {test01();system("pause");return 0;
}

key = 1 value = 10
key = 2 value = 20
key = 3 value = 30

key = 1 value = 10
key = 2 value = 20
key = 3 value = 30

key = 1 value = 10
key = 2 value = 20
key = 3 value = 30
 

map中所有元素都是成对出现,插入数据时候要使用对组

map大小和交换

功能描述:

  • 统计map容器大小以及交换map容器

函数原型:

  • size(); //返回容器中元素的数目
  • empty(); //判断容器是否为空
  • swap(st); //交换两个集合容器
#include<iostream>
#include<string> 
using namespace std;
#include <map>void printMap(map<int,int>&m)
{for (map<int, int>::iterator it = m.begin(); it != m.end(); it++){cout << "key = " << it->first << " value = " << it->second << endl;}cout << endl;
}void test01()
{map<int, int>m;m.insert(pair<int, int>(1, 10));m.insert(pair<int, int>(2, 20));m.insert(pair<int, int>(3, 30));if (m.empty()){cout << "m为空" << endl;}else{cout << "m不为空" << endl;cout << "m的大小为: " << m.size() << endl;}
}//交换
void test02()
{map<int, int>m;m.insert(pair<int, int>(1, 10));m.insert(pair<int, int>(2, 20));m.insert(pair<int, int>(3, 30));map<int, int>m2;m2.insert(pair<int, int>(4, 100));m2.insert(pair<int, int>(5, 200));m2.insert(pair<int, int>(6, 300));cout << "交换前" << endl;printMap(m);printMap(m2);cout << "交换后" << endl;m.swap(m2);printMap(m);printMap(m2);
}int main() {test01();test02();system("pause");return 0;
}

m不为空
m的大小为: 3
交换前
key = 1 value = 10
key = 2 value = 20
key = 3 value = 30

key = 4 value = 100
key = 5 value = 200
key = 6 value = 300

交换后
key = 4 value = 100
key = 5 value = 200
key = 6 value = 300

key = 1 value = 10
key = 2 value = 20
key = 3 value = 30

map插入和删除

功能描述:

  • map容器进行插入数据和删除数据

函数原型:

  • insert(elem); //在容器中插入元素。
  • clear(); //清除所有元素
  • erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。
  • erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
  • erase(key); //删除容器中值为key的元素。
#include<iostream>
#include<string> 
using namespace std;
#include <map>void printMap(map<int,int>&m)
{for (map<int, int>::iterator it = m.begin(); it != m.end(); it++){cout << "key = " << it->first << " value = " << it->second << endl;}cout << endl;
}void test01()
{//插入map<int, int> m;//第一种插入方式m.insert(pair<int, int>(1, 10));//第二种插入方式m.insert(make_pair(2, 20));//第三种插入方式m.insert(map<int, int>::value_type(3, 30));//第四种插入方式m[4] = 40; printMap(m);//删除m.erase(m.begin());printMap(m);m.erase(3);printMap(m);//清空m.erase(m.begin(),m.end());m.clear();printMap(m);
}int main() {test01();system("pause");return 0;
}

key = 1 value = 10
key = 2 value = 20
key = 3 value = 30
key = 4 value = 40

key = 2 value = 20
key = 3 value = 30
key = 4 value = 40

key = 2 value = 20
key = 4 value = 40

map查找和统计

功能描述:

  • 对map容器进行查找数据以及统计数据

函数原型:

  • find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
  • count(key); //统计key的元素个数
#include<iostream>
#include<string> 
using namespace std;
#include <map>//查找和统计
void test01()
{map<int, int>m; m.insert(pair<int, int>(1, 10));m.insert(pair<int, int>(2, 20));m.insert(pair<int, int>(3, 30));//查找map<int, int>::iterator pos = m.find(2);if (pos != m.end()){cout << "找到了元素 key = " << (*pos).first << " value = " << (*pos).second << endl;}else{cout << "未找到元素" << endl;}//统计int num = m.count(3);cout << "num = " << num << endl;
}int main() {test01();system("pause");return 0;
}

找到了元素 key = 2 value = 20
num = 1

map容器排序

  • 利用仿函数可以指定map容器的排序规则
  • 对于自定义数据类型,map必须要指定排序规则,同set容器
#include<iostream>
#include<string> 
using namespace std;
#include <map>class MyCompare {
public:bool operator()(int v1, int v2) {return v1 > v2;}
};void test01() 
{//默认从小到大排序//利用仿函数实现从大到小排序map<int, int, MyCompare> m;m.insert(make_pair(1, 10));m.insert(make_pair(2, 20));m.insert(make_pair(3, 30));m.insert(make_pair(4, 40));m.insert(make_pair(5, 50));for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) {cout << "key:" << it->first << " value:" << it->second << endl;}
}
int main() {test01();system("pause");return 0;
}

key:5 value:50
key:4 value:40
key:3 value:30
key:2 value:20
key:1 value:10

map / multimap总结

1. map是关联容器,它按照特定的次序(按照key来比较)存储由键值key和值value组合而成的元素。

2. 在map中,键值key通常用于排序和惟一地标识元素,而值value中存储与此键值key关联的

内容。键值key和值value的类型可能不同,并且在map的内部,key与value通过成员类型

value_type绑定在一起,为其取别名称为pair: typedef pair<const key, T> value_type;

3. 在内部,map中的元素总是按照键值key进行比较排序的。

4. map中通过键值访问单个元素的速度通常比unordered_map容器慢,但map允许根据顺序

对元素进行直接迭代(即对map中的元素进行迭代时,可以得到一个有序的序列)。

5. map支持下标访问符,即在[]中放入key,就可以找到与key对应的value。

6. map通常被实现为二叉搜索树(更准确的说:平衡二叉搜索树(红黑树))。

注意:multimap与map最大区别就是不支持operator[]传值(key的唯一性)

OJ练习

set的算法常用方式

 两个数组的交集

 利用set去重并排序

class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {set<int> s1;for(auto e:nums1) s1.insert(e);set<int> s2;for(auto e:nums2) s2.insert(e);vector<int> v;for(auto e1:s1){if(s2.count(e1)) v.push_back(e1);}return v;}
};

set的算法常用方式

字符串中的第一个唯一字符

经典哈希表存储频数方法

class Solution {
public:int firstUniqChar(string s) {map<int,int> m;for(auto ch:s) m[ch]++;for(int i=0;i<s.size();i++){if(m[s[i]]==1) return i;}return -1;}
};

只出现一次的数字 II

 对于map的范围for:

map<int,string> mp;
for(auto [key值,value值] : mp)
class Solution {
public:int singleNumber(vector<int>& nums) {map<int,int> m;for(int n:nums){m[n]++;}int ret;for(auto [n,ac]:m){if(ac==1) {ret=n;break;}}return ret;}};

面试题 01.04. 回文排列

class Solution {
public:bool canPermutePalindrome(string s) {unordered_map<char, int> tempMP;for (char c:s) {tempMP[c]++;}int time = 0; //记录奇数次字母的个数for (auto [first, second] : tempMP) {if (second % 2) {if(++time > 1) return false;//若超过1个则不可能对称形成回文}}return true;}
};

692. 前K个高频单词 - 力扣(LeetCode)

单词识别_牛客题霸_牛客网 (nowcoder)

更多推荐

进阶C++

本文发布于:2023-12-03 11:05:09,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1654657.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:进阶

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!