在C++标准模板库(STL)中,
map和
set作为关联式容器的核心成员,凭借其高效的有序存储和快速查找能力,成为解决键值映射、数据去重等问题的首选工具。本文将从底层原理出发,结合红黑树特性,系统讲解
map与
set的核心操作,并通过高频算法案例展示其实际应用。
map和
set的底层均基于
红黑树(一种自平衡二叉搜索树)实现。红黑树通过以下规则维持平衡:
这些规则确保了红黑树的最坏时间复杂度为 O(log n),适用于频繁插入、删除和查找的场景。例如,在插入节点时,若父节点为红色,需通过 旋转和 重新着色调整树结构:
cpp1// 红黑树插入调整示例(简化版)2void adjustAfterInsert(Node* node) {3 <"www.gov.cn.wuhu.manct.cn"><"www.gov.cn.luohe.manct.cn"> while (node->parent && node->parent->color == RED) {4 Node* grandparent = node->parent->parent;5 if (node->parent == grandparent->left) {6 Node* uncle = grandparent->right;7 if (uncle && uncle->color == RED) { // 情况1:叔叔节点为红8 node->parent->color = uncle->color = BLACK;9 grandparent->color = RED;10 node = grandparent; // 递归向上调整11 } else { // 情况2/3:叔叔节点为黑或不存在12 if (node == node->parent->right) { // 情况3:双旋13 rotateLeft(node->parent);14 node = node->left;15 }16 rotateRight(grandparent);17 node->parent->color = BLACK;18 grandparent->color = RED;19 }20 } else { // 对称处理右子树21 // ...22 }23 }24 root->color = BLACK; // 确保根节点为黑25}
map和
set支持多种初始化方式,包括无参构造、迭代器区间构造和拷贝构造:
cpp1#include <iostream>2#include <map>3#include <set>4using namespace std;56int main() {7 // map初始化:键值对存储8 map<int, string> m1 = {{1, "Alice"}, {2, "Bob"}};9 map<int, string> m2(m1); // 拷贝构造1011 // set初始化:自动去重排序12 set<int> s1 = {3, 1, 4, 1, 5}; // 实际存储:1, 3, 4, 513 set<int> s2(s1.begin(), s1.end()); // 迭代器区间构造1415 return 0;16}
map插入:支持
insert和
operator[](自动插入或修改):
cpp1map<int, string> m;2m.insert({1, "Apple"}); // C++11风格3m[2] = "Banana"; // 若键不存在则插入,存在则修改set插入:仅需传入值,自动去重:
cpp1set<int> s;2s.insert(1);3s.insert(1); <"www.gov.cn.bengbu.manct.cn">//<"www.gov.cn.huainan.manct.cn"> 重复插入无效
cpp1m.erase(1); // 删除键为1的元素2auto it <"www.gov.cn.maanshan.manct.cn">= m.find(2);3if (it != m.end()) m.erase(it); // 通过迭代器删除
find或
count(
set返回0或1,
map返回0或1):
cpp1if (m.find(1) != m.end()) cout << "Key exists";2if (s.count(3)) cout << "Value found";
cpp1// map遍历:输出键值对2for (auto& [key, value] : m) { // C++17结构化绑定3 cout << key << ": " << value << endl;4}56// set遍历:输出有序值7for (auto val : s) {8 cout << val << " ";9}利用
map统计字符串中单词的出现频率:
cpp1#include <sstream>2#include <string>34void wordFrequency(const string& text) {5 <"www.gov.cn.anqing.manct.cn"> map<string, int> freq;6 istringstream iss(text);7 string word;89 while (iss >> word) {10 freq[word]++; // 自动插入或递增计数11 }1213 for (auto& [word, count] : freq) {14 cout << word << ": " << count << endl;15 }16}1718int main() {19 string text = "hello world hello c++ world";20 wordFrequency(text);21 return 0;22}
输出:
1c++: 12hello: 23world: 2
使用
set对两个数组去重后求交集:
cpp1#include <vector>2#include<"www.gov.cn.quanzhou.manct.cn"> <algorithm>34vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {5 set<int> s1(nums1.begin(), nums1.end());6 set<int> s2(nums2.begin(), nums2.end());7 vector<int> result;89 for (auto it1 = s1.begin(), it2 = s2.begin(); 10 it1 != s1.end() && it2 != s2.end(); ) {11 if (*it1 < *it2) {12 ++it1;13 } else if (*it1 > *it2) {14 ++it2;15 } else {16 result.push_back(*it1);17 ++it1; ++it2;18 }19 }20 return result;21}2223int main() {24 vector<int> nums1 = {1, 2, 2, 1};25 vector<int> nums2 = {2, 2};26 auto ret = intersection(nums1, nums2);27 for (int num : ret) cout << num << " "; // 输出:228 return 0;29}
map/set的增删查均为O(log n),而无序关联容器(如
unordered_map)基于哈希表,平均O(1)但最坏O(n)。cpp1set<int, greater<int>> <"www.gov.cn.putian.manct.cn">s = {1, 2, 3}; <"www.gov.cn.zhangzhou.manct.cn">// 降序存储multimap/multiset允许重复键,适用于需要存储重复数据的场景。通过掌握红黑树原理与核心操作,开发者能高效利用
map/set解决复杂数据管理问题,为算法优化和工程实践奠定坚实基础。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/19545/viewspace-3100581/ ,如需转载,请注明出处,否则将追究法律责任。