浅谈C++ 容器查找效率

 更新时间:2025年06月27日 10:02:44   作者:pumpkin84514  
本文主要介绍了浅谈C++ STL容器的查找效率差异,对比vector、list、set/map、unordered_set和deque等,帮助选择合适容器以优化性能,感兴趣的可以了解一下

只要选对容器,多写几行代码就能让程序“飞”起来。下面用生活化的比喻 + 足够多的带注释示例,帮你弄懂常用 STL 容器的查找特性。
读完你应该能快速判断:“我的场景该用哪一个?”

0. 先把“查找复杂度”聊明白

记号含义举个🌰
O(1)常数时间像从冰箱门口拿饮料——一下就到手
O(log n)对数时间折半查电话簿——越找越快
O(n)线性时间排队买奶茶——要挨个等

只要记住:数字越小越快,O(1) 最爽,O(n) 最慢。

1. std::vector —— “排排坐”的长桌子

特点:元素一字排开,内存连续,跟操场跑道一样直。

查找

  • 没排序:只能一个个比——O(n)
  • 排好序:可折半查——O(log n)
#include <vector>
#include <algorithm>   // std::sort, std::binary_search
#include <iostream>

int main() {
    std::vector<int> nums{5, 1, 4, 3, 2};   // 连续摆放的「长桌子」
    
    std::sort(nums.begin(), nums.end());    // ① 排序一次,之后查找快
                                            //    nums 变成 {1,2,3,4,5}
    bool has3 = std::binary_search(         // ② 折半查找 3
        nums.begin(), nums.end(), 3);       //    O(log n)
    
    std::cout << (has3 ? "找到了" : "没找到") << '\n';
}

什么时候用

  • 数据量可控、想要下标随机访问。
  • 插入删除不多(尤其不是在中间插)。

2. std::list —— “珍珠项链”

  • 特点:每颗珠子(节点)用线(指针)串起来,插拔容易。
  • 查找:得一颗颗摸——O(n),而且分散指针不利于 CPU 缓存。
#include <list>
#include <algorithm>
#include <iostream>

int main() {
    std::list<int> lst{1, 2, 3, 4, 5};          // 一串节点
    
    auto it = std::find(lst.begin(), lst.end(), 3); // ① 线性查找
    std::cout << (it != lst.end() ? "找到了" : "没找到") << '\n';
}

什么时候用插入 / 删除动作特别频繁、但不太在意查找速度,比如任务队列需要随时插入或移走元素。

3. std::set —— 自动排序的“有序字典”

  • 底层:红黑树,像一个能自动平衡的家谱图。
  • 查找 / 增删:都 O(log n)。
#include <set>
#include <iostream>

int main() {
    std::set<int> s{4, 1, 3, 2};      // 元素自动有序:{1,2,3,4}

    bool has2 = s.contains(2);        // C++20 起可直接 contains
    std::cout << (has2 ? "有 2" : "没 2") << '\n';
}

什么时候用既想要“去重”又想要“元素排好序”,而且单个元素查找要快。

4. std::unordered_set —— “散列表”小黑屋

  • 底层:哈希表,把元素按哈希值分到不同“桶”里。
  • 平均查找:O(1),最坏冲突多时 O(n)。
  • 元素无序:放进去啥顺序不管。
#include <unordered_set>
#include <iostream>

int main() {
    std::unordered_set<std::string> words; // 小黑屋摞桶
    words.insert("hello");
    words.insert("world");

    if (words.contains("hello")) {         // 平均 O(1)
        std::cout << "嘿~ 找到了 hello\n";
    }
}

什么时候用不需要顺序,只想“秒查秒存”,典型如去重、统计次数。

5. std::map vs std::unordered_map —— 键值对“双子星”

容器底层查找是否有序
map红黑树O(log n)
unordered_map哈希表O(1) 平均
#include <map>
#include <unordered_map>
#include <iostream>

int main() {
    std::map<int, std::string> ordered;          // 有序
    ordered[2] = "B"; ordered[1] = "A";

    std::unordered_map<int, std::string> hash;   // 无序
    hash[2] = "B"; hash[1] = "A";

    std::cout << ordered[1] << ' ' << hash[1] << '\n';
}

什么时候用

  • 需要按键遍历且保持有序:map
  • 只关心查、增、删速度:unordered_map

6. std::deque —— 可以从两头装菜的“长盘子”

  • 特点:首尾插入 / 删除都是 O(1);中间操作比 vector 慢点。
  • 查找:线性 O(n);随机访问语法与 vector 一样。
#include <deque>
#include <algorithm>
#include <iostream>

int main() {
    std::deque<int> q{1, 2, 3};
    q.push_front(0);        // 头部 O(1)
    q.push_back(4);         // 尾部 O(1)

    bool has3 = std::find(q.begin(), q.end(), 3) != q.end();
    std::cout << (has3 ? "有 3" : "没 3") << '\n';
}

什么时候用既想要随机访问,又要在首尾频繁加减元素,比如滑动窗口算法。

7. “多索引”技巧 —— 一份数据,多把钥匙

如果你既想按 ID 查,又想按 名字 查,可以:

#include <vector>
#include <unordered_map>

struct User { int id; std::string name; };

std::vector<User> users;                      // 主数组
std::unordered_map<int, User*> id_index;      // id → 指针
std::unordered_map<std::string, User*> name_index; // name → 指针
  • 插入一个用户时,三处都要更新
  • 查找时,从对应索引直接拿到指针,速度飞快。

8. 记忆卡片(纯中文朗朗上口)

小而随机选 vector
插删中间选 list
要有序就 set/map
求极致快 unordered_*
两头忙活用 deque
多条件查 自建索引

最后一句话

先写代码,测一次性能——复杂度只给方向,真快还是得跑数据。祝你写得顺、跑得飞!

到此这篇关于浅谈C++ 容器查找效率的文章就介绍到这了,更多相关C++ 容器查找效率内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

您可能感兴趣的文章:

相关文章

  • C语言深入探究水仙花数与变种水仙花数代码

    C语言深入探究水仙花数与变种水仙花数代码

    求水仙花数和变种水仙花数是非常适合初学者学习的代码,其中包含的循环和逻辑方式等知识点。这既能起到对以往知识的复习,也可以学习到一种不同的逻辑思考方式
    2022-05-05
  • 详解C++编程中运算符的使用

    详解C++编程中运算符的使用

    这篇文章主要介绍了详解C++编程中运算符的使用,是C++入门学习中的基础知识,需要的朋友可以参考下
    2015-09-09
  • linux C 打印错误信息和标准输入输出详细介绍

    linux C 打印错误信息和标准输入输出详细介绍

    这篇文章主要介绍了linux C 打印错误信息和标准输入输出详细介绍的相关资料,需要的朋友可以参考下
    2016-12-12
  • C++begin和end运算符的返回迭代器的类型如何判断?

    C++begin和end运算符的返回迭代器的类型如何判断?

    今天小编就为大家分享一篇关于C++begin和end运算符的返回迭代器的类型如何判断?,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04
  • C语言字符串函数入门

    C语言字符串函数入门

    这篇文章主要为大家介绍了C语言字符串函数,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • C++中动态内存管理的实现

    C++中动态内存管理的实现

    本文主要介绍了C++中动态内存管理的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-09-09
  • C语言中定义与声明有哪些区别

    C语言中定义与声明有哪些区别

    在C/C++中有一个基础且重要的知识,什么是声明?什么是定义?他们的区别是什么?本文将带你理清其中的区别
    2022-07-07
  • C++调用C函数实例详解

    C++调用C函数实例详解

    这篇文章主要介绍了C++调用C函数实例详解的相关资料,需要的朋友可以参考下
    2017-07-07
  • C++中的常用库

    C++中的常用库

    这篇文章主要介绍了C++中的常用库,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-05-05
  • 深入解析C++中类的多重继承

    深入解析C++中类的多重继承

    这篇文章主要介绍了深入解析C++中类的多重继承,包括多重继承相关的二义性问题,需要的朋友可以参考下
    2015-09-09

最新评论