Skip to content

C++ STL 容器

概述

STL(Standard Template Library)容器是C++标准库提供的数据结构模板。容器封装了常用的数据结构,提供统一的接口和高效的实现。本章介绍序列容器、关联容器、无序容器的使用方法和性能特点。

📦 序列容器

vector - 动态数组

cpp
#include <iostream>
#include <vector>
#include <algorithm>

class VectorDemo {
public:
    static void basicOperations() {
        std::cout << "=== vector基本操作 ===" << std::endl;
        
        // 初始化
        std::vector<int> vec1;                    // 空向量
        std::vector<int> vec2(5, 10);            // 5个10
        std::vector<int> vec3{1, 2, 3, 4, 5};    // 初始化列表
        
        // 添加元素
        vec1.push_back(1);
        vec1.push_back(2);
        vec1.emplace_back(3);  // 就地构造
        
        // 访问元素
        std::cout << "第一个元素: " << vec1[0] << std::endl;
        std::cout << "最后一个元素: " << vec1.back() << std::endl;
        
        // 迭代器
        std::cout << "所有元素: ";
        for (auto it = vec1.begin(); it != vec1.end(); ++it) {
            std::cout << *it << " ";
        }
        std::cout << std::endl;
        
        // 范围for循环
        std::cout << "范围for: ";
        for (const auto& element : vec1) {
            std::cout << element << " ";
        }
        std::cout << std::endl;
    }
    
    static void capacityManagement() {
        std::cout << "\n=== vector容量管理 ===" << std::endl;
        
        std::vector<int> vec;
        
        std::cout << "初始容量: " << vec.capacity() << std::endl;
        
        for (int i = 0; i < 10; ++i) {
            vec.push_back(i);
            std::cout << "大小: " << vec.size() 
                      << ", 容量: " << vec.capacity() << std::endl;
        }
        
        // 预分配空间
        std::vector<int> vec2;
        vec2.reserve(100);
        std::cout << "预分配后容量: " << vec2.capacity() << std::endl;
        
        // 缩减容量
        vec.shrink_to_fit();
        std::cout << "缩减后容量: " << vec.capacity() << std::endl;
    }
    
    static void modifyOperations() {
        std::cout << "\n=== vector修改操作 ===" << std::endl;
        
        std::vector<int> vec{1, 2, 3, 4, 5};
        
        // 插入
        vec.insert(vec.begin() + 2, 99);  // 在位置2插入99
        
        // 删除
        vec.erase(vec.begin());           // 删除第一个元素
        vec.erase(vec.begin(), vec.begin() + 2);  // 删除范围
        
        // 查找和算法
        auto it = std::find(vec.begin(), vec.end(), 99);
        if (it != vec.end()) {
            std::cout << "找到99在位置: " << std::distance(vec.begin(), it) << std::endl;
        }
        
        // 排序
        std::sort(vec.begin(), vec.end());
        
        std::cout << "最终结果: ";
        for (int n : vec) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
    }
};

int main() {
    VectorDemo::basicOperations();
    VectorDemo::capacityManagement();
    VectorDemo::modifyOperations();
    
    return 0;
}

deque - 双端队列

cpp
#include <iostream>
#include <deque>
#include <algorithm>

class DequeDemo {
public:
    static void demonstrate() {
        std::cout << "=== deque双端队列 ===" << std::endl;
        
        std::deque<int> dq;
        
        // 双端添加
        dq.push_back(1);
        dq.push_back(2);
        dq.push_front(0);
        dq.push_front(-1);
        
        std::cout << "双端添加后: ";
        for (int n : dq) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // 随机访问
        std::cout << "第二个元素: " << dq[1] << std::endl;
        std::cout << "第三个元素: " << dq.at(2) << std::endl;
        
        // 双端删除
        dq.pop_front();
        dq.pop_back();
        
        std::cout << "双端删除后: ";
        for (int n : dq) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // 中间插入删除
        dq.insert(dq.begin() + 1, 10);
        dq.erase(dq.end() - 1);
        
        std::cout << "中间操作后: ";
        for (int n : dq) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
    }
};

list - 双向链表

cpp
#include <iostream>
#include <list>
#include <algorithm>

class ListDemo {
public:
    static void demonstrate() {
        std::cout << "\n=== list双向链表 ===" << std::endl;
        
        std::list<int> lst{3, 1, 4, 1, 5};
        
        // 链表特有操作
        lst.push_front(0);
        lst.push_back(6);
        
        std::cout << "初始链表: ";
        for (int n : lst) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // 排序(链表专用)
        lst.sort();
        std::cout << "排序后: ";
        for (int n : lst) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // 去重
        lst.unique();
        std::cout << "去重后: ";
        for (int n : lst) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // 反转
        lst.reverse();
        std::cout << "反转后: ";
        for (int n : lst) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // 合并
        std::list<int> lst2{2, 7, 8};
        lst2.sort();
        lst.merge(lst2);
        
        std::cout << "合并后: ";
        for (int n : lst) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
    }
};

🗂️ 关联容器

set - 有序集合

cpp
#include <iostream>
#include <set>
#include <string>

class SetDemo {
public:
    static void demonstrate() {
        std::cout << "\n=== set有序集合 ===" << std::endl;
        
        std::set<int> s{3, 1, 4, 1, 5, 9, 2, 6};  // 自动去重和排序
        
        std::cout << "set内容: ";
        for (int n : s) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // 插入
        auto [it, inserted] = s.insert(7);
        std::cout << "插入7: " << (inserted ? "成功" : "失败") << std::endl;
        
        auto [it2, inserted2] = s.insert(3);  // 重复元素
        std::cout << "插入3: " << (inserted2 ? "成功" : "失败") << std::endl;
        
        // 查找
        if (s.find(4) != s.end()) {
            std::cout << "找到元素4" << std::endl;
        }
        
        if (s.count(10) > 0) {
            std::cout << "找到元素10" << std::endl;
        } else {
            std::cout << "未找到元素10" << std::endl;
        }
        
        // 删除
        s.erase(1);
        auto it_range = s.equal_range(5);
        s.erase(it_range.first, it_range.second);
        
        std::cout << "删除后: ";
        for (int n : s) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
    }
    
    static void customComparator() {
        std::cout << "\n=== 自定义比较器 ===" << std::endl;
        
        // 降序set
        std::set<int, std::greater<int>> desc_set{3, 1, 4, 1, 5};
        
        std::cout << "降序set: ";
        for (int n : desc_set) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // 自定义比较器
        auto cmp = [](const std::string& a, const std::string& b) {
            return a.length() < b.length();
        };
        
        std::set<std::string, decltype(cmp)> str_set(cmp);
        str_set.insert("hello");
        str_set.insert("hi");
        str_set.insert("world");
        str_set.insert("cpp");
        
        std::cout << "按长度排序: ";
        for (const auto& s : str_set) {
            std::cout << s << " ";
        }
        std::cout << std::endl;
    }
};

map - 有序映射

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

class MapDemo {
public:
    static void demonstrate() {
        std::cout << "\n=== map有序映射 ===" << std::endl;
        
        std::map<std::string, int> word_count;
        
        // 插入方式
        word_count["hello"] = 1;
        word_count.insert({"world", 2});
        word_count.emplace("cpp", 3);
        
        // 访问
        std::cout << "hello出现次数: " << word_count["hello"] << std::endl;
        std::cout << "world出现次数: " << word_count.at("world") << std::endl;
        
        // 遍历
        std::cout << "所有单词统计:" << std::endl;
        for (const auto& [word, count] : word_count) {
            std::cout << word << ": " << count << std::endl;
        }
        
        // 查找
        auto it = word_count.find("cpp");
        if (it != word_count.end()) {
            std::cout << "找到 " << it->first << ": " << it->second << std::endl;
        }
        
        // 删除
        word_count.erase("hello");
        
        std::cout << "删除hello后大小: " << word_count.size() << std::endl;
    }
    
    static void multimap_demo() {
        std::cout << "\n=== multimap多重映射 ===" << std::endl;
        
        std::multimap<std::string, int> multi_map;
        
        multi_map.insert({"apple", 100});
        multi_map.insert({"apple", 200});
        multi_map.insert({"banana", 150});
        multi_map.insert({"apple", 300});
        
        std::cout << "multimap内容:" << std::endl;
        for (const auto& [key, value] : multi_map) {
            std::cout << key << ": " << value << std::endl;
        }
        
        // 查找范围
        auto range = multi_map.equal_range("apple");
        std::cout << "apple的所有值: ";
        for (auto it = range.first; it != range.second; ++it) {
            std::cout << it->second << " ";
        }
        std::cout << std::endl;
    }
};

🔗 无序容器

unordered_set - 哈希集合

cpp
#include <iostream>
#include <unordered_set>
#include <unordered_map>
#include <string>

class UnorderedDemo {
public:
    static void unordered_set_demo() {
        std::cout << "\n=== unordered_set哈希集合 ===" << std::endl;
        
        std::unordered_set<int> uset{3, 1, 4, 1, 5, 9, 2, 6};
        
        std::cout << "unordered_set内容: ";
        for (int n : uset) {
            std::cout << n << " ";
        }
        std::cout << std::endl;
        
        // 性能信息
        std::cout << "桶数量: " << uset.bucket_count() << std::endl;
        std::cout << "负载因子: " << uset.load_factor() << std::endl;
        std::cout << "最大负载因子: " << uset.max_load_factor() << std::endl;
        
        // 查找性能:O(1)平均
        auto start = std::chrono::high_resolution_clock::now();
        bool found = uset.find(5) != uset.end();
        auto end = std::chrono::high_resolution_clock::now();
        
        std::cout << "查找结果: " << (found ? "找到" : "未找到") << std::endl;
    }
    
    static void unordered_map_demo() {
        std::cout << "\n=== unordered_map哈希映射 ===" << std::endl;
        
        std::unordered_map<std::string, int> umap;
        
        // 插入
        umap["apple"] = 100;
        umap["banana"] = 200;
        umap["orange"] = 150;
        
        // 遍历(顺序不确定)
        std::cout << "unordered_map内容:" << std::endl;
        for (const auto& [key, value] : umap) {
            std::cout << key << ": " << value << std::endl;
        }
        
        // 查找性能
        auto it = umap.find("apple");
        if (it != umap.end()) {
            std::cout << "快速找到: " << it->first << std::endl;
        }
        
        // 自定义哈希
        struct Point {
            int x, y;
            bool operator==(const Point& other) const {
                return x == other.x && y == other.y;
            }
        };
        
        struct PointHash {
            size_t operator()(const Point& p) const {
                return std::hash<int>{}(p.x) ^ (std::hash<int>{}(p.y) << 1);
            }
        };
        
        std::unordered_set<Point, PointHash> point_set;
        point_set.insert({1, 2});
        point_set.insert({3, 4});
        
        std::cout << "点集合大小: " << point_set.size() << std::endl;
    }
};

📊 容器性能比较

性能测试

cpp
#include <iostream>
#include <vector>
#include <list>
#include <set>
#include <unordered_set>
#include <chrono>
#include <random>

class PerformanceTest {
public:
    static void compareInsertion() {
        std::cout << "\n=== 插入性能比较 ===" << std::endl;
        
        const int N = 100000;
        std::random_device rd;
        std::mt19937 gen(rd());
        std::uniform_int_distribution<> dis(1, 1000000);
        
        // vector尾部插入
        {
            std::vector<int> vec;
            vec.reserve(N);
            
            auto start = std::chrono::high_resolution_clock::now();
            for (int i = 0; i < N; ++i) {
                vec.push_back(dis(gen));
            }
            auto end = std::chrono::high_resolution_clock::now();
            
            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
            std::cout << "vector尾部插入: " << duration.count() << "ms" << std::endl;
        }
        
        // list插入
        {
            std::list<int> lst;
            
            auto start = std::chrono::high_resolution_clock::now();
            for (int i = 0; i < N; ++i) {
                lst.push_back(dis(gen));
            }
            auto end = std::chrono::high_resolution_clock::now();
            
            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
            std::cout << "list插入: " << duration.count() << "ms" << std::endl;
        }
        
        // set插入
        {
            std::set<int> s;
            
            auto start = std::chrono::high_resolution_clock::now();
            for (int i = 0; i < N; ++i) {
                s.insert(dis(gen));
            }
            auto end = std::chrono::high_resolution_clock::now();
            
            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
            std::cout << "set插入: " << duration.count() << "ms" << std::endl;
        }
        
        // unordered_set插入
        {
            std::unordered_set<int> us;
            
            auto start = std::chrono::high_resolution_clock::now();
            for (int i = 0; i < N; ++i) {
                us.insert(dis(gen));
            }
            auto end = std::chrono::high_resolution_clock::now();
            
            auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
            std::cout << "unordered_set插入: " << duration.count() << "ms" << std::endl;
        }
    }
};

int main() {
    VectorDemo::basicOperations();
    VectorDemo::capacityManagement();
    VectorDemo::modifyOperations();
    
    DequeDemo::demonstrate();
    ListDemo::demonstrate();
    
    SetDemo::demonstrate();
    SetDemo::customComparator();
    
    MapDemo::demonstrate();
    MapDemo::multimap_demo();
    
    UnorderedDemo::unordered_set_demo();
    UnorderedDemo::unordered_map_demo();
    
    PerformanceTest::compareInsertion();
    
    return 0;
}

总结

STL容器提供了丰富的数据结构选择,各有特点和适用场景:

容器分类

  • 序列容器: vector, deque, list, array
  • 关联容器: set, map, multiset, multimap
  • 无序容器: unordered_set, unordered_map等

性能特点

容器随机访问插入删除查找
vectorO(1)O(1)尾部O(n)O(n)
dequeO(1)O(1)两端O(n)O(n)
listO(n)O(1)O(1)O(n)
setO(n)O(log n)O(log n)O(log n)
unordered_setO(n)O(1)平均O(1)平均O(1)平均

选择指南

  • 频繁随机访问: vector
  • 双端操作: deque
  • 频繁中间插入删除: list
  • 需要排序去重: set
  • 快速查找: unordered_set
  • 键值对存储: map/unordered_map

STL容器是C++程序的基础构件,选择合适的容器能显著提升程序性能。

本站内容仅供学习和研究使用。