当前位置: 首页 > news >正文

异构比较查找

1. 核心概念

异构比较查找指:在关联式容器里,用“与键类型不同但可比较/可哈希的类型”进行查找、计数、边界查询与删除,而无需构造临时的键对象或产生分配开销。
典型收益:用 std::string_view/const char*std::map<std::string, …>std::unordered_map<std::string, …> 中查找,避免创建临时 std::string

2. 适用范围与标准版本

  • 有序容器(树)std::map / std::set / std::multimap / std::multiset
    自 C++14 起支持异构查找,前提是比较器是透明的
  • 无序容器(哈希)std::unordered_map / std::unordered_set 及其 multi 变体
    自 C++20 起支持异构查找,前提是哈希器与相等谓词均为透明,且它们能接受异构类型。

3. 如何“启用”异构查找

3.1 有序容器:使用透明比较器

  • 直接使用标准的 std::less<>(注意带尖括号空模板参数),它是透明的。

  • 或自定义比较器,需:

    1. 提供模板/重载,能比较键类型与目标查询类型;
    2. 定义嵌套别名 using is_transparent = void; 表示“透明”。

透明后,以下成员可接受异构类型:find / count / lower_bound / upper_bound / equal_range / erase(key)(C++14 起)/ contains(C++20 起)。

3.2 无序容器:透明哈希与透明相等

  • 提供可接收异构类型的哈希器与相等谓词;并各自声明 using is_transparent = void;

  • 常见做法(键为 std::string):

    • 哈希器std::hash<std::string_view>(其 operator() 接收 std::string_view,可从 std::string/const char* 隐式转换获得);
    • 相等谓词std::equal_to<>(透明)。
  • 也可自定义哈希器/相等谓词以支持大小写不敏感等策略,但要确保二者一致性(“相等 ⇒ 同哈希”)。

4. 实战示例

示例 A:在 std::map<std::string, int> 中用 std::string_view/const char* 查找(C++14+)

#include <map>
#include <string>
#include <string_view>
#include <iostream>int main() {// 使用透明比较器 std::less<>,而不是 std::less<std::string>std::map<std::string, int, std::less<>> m{{"apple", 1}, {"banana", 2}, {"cherry", 3}};// 用 string_view 查找:不会分配内存或构造临时 std::stringstd::string_view key_sv = "banana";if (auto it = m.find(key_sv); it != m.end())std::cout << it->first << " => " << it->second << '\n';// 用 const char* 查找if (auto it = m.find("cherry"); it != m.end())std::cout << it->first << " => " << it->second << '\n';// 异构边界查询auto lb = m.lower_bound("banana"); // const char* 也可if (lb != m.end())std::cout << "lower_bound: " << lb->first << '\n';
}

要点:

  • 关键在于 std::less<>透明的并接受异构比较;
  • 若用默认的 std::less<std::string>,则不具备异构查找能力。

示例 B:大小写不敏感的 std::set<std::string> 异构查找(自定义透明比较器,C++14+)

#include <set>
#include <string>
#include <string_view>
#include <cctype>struct ci_less {using is_transparent = void; // 声明透明// 统一转小写逐字符比较(示例简化,未处理 locale)static int cmp(std::string_view a, std::string_view b) {auto tolow = [](unsigned char c){ return std::tolower(c); };size_t n = std::min(a.size(), b.size());for (size_t i = 0; i < n; ++i) {int da = tolow(a[i]), db = tolow(b[i]);if (da != db) return da - db;}return (a.size() < b.size()) ? -1 : (a.size() > b.size());}bool operator()(std::string_view a, std::string_view b) const {return cmp(a, b) < 0;}// 若需要,也可额外提供重载以支持更多类型
};int main() {std::set<std::string, ci_less> S = {"Apple", "banana", "Cherry"};// 用 const char* 查auto it1 = S.find("BANANA");// 用 string_view 查std::string_view key = "cherry";auto it2 = S.find(key);
}

要点:

  • 比较器需对所有可能参与比较的类型给出严格弱序(strict weak ordering)。
  • is_transparent 是开启异构接口的“开关”。

示例 C:std::unordered_map<std::string, int> 的异构查找(C++20+)

#include <unordered_map>
#include <string>
#include <string_view>
#include <iostream>
#include <functional>struct sv_hash {using is_transparent = void;  // 透明using is_avalanching = void;  //(可选,给库优化用)size_t operator()(std::string_view sv) const noexcept {return std::hash<std::string_view>{}(sv);}// 允许以 std::string、const char* 直接入参(均可隐式转为 string_view)size_t operator()(const char* s) const noexcept {return std::hash<std::string_view>{}(std::string_view{s});}size_t operator()(const std::string& s) const noexcept {return std::hash<std::string_view>{}(s);}
};struct sv_equal {using is_transparent = void;  // 透明bool operator()(std::string_view a, std::string_view b) const noexcept {return a == b;}bool operator()(const char* a, std::string_view b) const noexcept {return std::string_view{a} == b;}bool operator()(std::string_view a, const char* b) const noexcept {return a == std::string_view{b};}
};int main() {// 键类型仍是 std::string,但哈希与相等谓词对异构类型透明std::unordered_map<std::string, int, sv_hash, sv_equal> um{{"alpha", 1}, {"beta", 2}, {"gamma", 3}};if (auto it = um.find("beta"); it != um.end())std::cout << it->first << " => " << it->second << '\n';std::string_view key = "gamma";if (um.contains(key))std::cout << "contains gamma\n";// C++20 起 erase 也可用异构键um.erase("alpha");
}

要点:

  • 无序容器需要“哈希器 + 相等谓词”同时透明,并能接收异构类型;
  • 切记两者要一致:相等则哈希相等(或至少冲突概率相当),否则行为/性能不可预期。

5. 常见问题与陷阱

  1. 别忘了透明性

    • 有序容器用 std::less<> 或自定义并含 is_transparent 的比较器;
    • 无序容器的哈希器与相等谓词都要提供 is_transparent,且能处理异构入参。
  2. std::string_view 的生命周期
    查找阶段用 string_view 没问题,但往容器插入时仍要保证最终存储对象(如 std::string)拥有自己的内存;不要把指向临时的 string_view 保存下来。

  3. 顺序一致性/等价关系(有序容器):
    自定义比较器必须对所有可能比较的类型定义同一套严格弱序

  4. 哈希/相等一致性(无序容器):
    “相等 ⇒ 哈希相等(或同分布)”必须在所有参与类型上成立。

  5. 标准版本差异

    • 树型容器异构查找:C++14 起成熟可用;
    • 哈希容器异构查找:C++20 起才在标准层面完善。旧编译器/库可能不完全支持。

6. 何时应使用

  • 频繁用只读视图(如 std::string_view)在 std::string 容器中查找;
  • 需要避免临时对象构造与内存分配;
  • 需要 lower_bound/upper_bound 等在不制造临时键的情况下执行边界查询。

7. 小结

  • 有序容器:把比较器换成 std::less<>(或自定义透明比较器)即可获得异构查找。
  • 无序容器:提供透明且可接收异构类型的哈希器与相等谓词(常配合 std::string_view)。
  • 这样可以减少拷贝与分配,显著优化查找路径上的延迟与吞吐。
http://www.dtcms.com/a/575318.html

相关文章:

  • 网站价位无法访问服务器上网站
  • 服装购物网站排名icp备案证书
  • 网站对公司的作用是什么意思免费外贸网站制作
  • 一级a做爰片免费网站体验nginx进wordpress不能进目录
  • 湛江市建设局网站成功的软文营销案例
  • 对于网站开发有什么要求冉冉科技网站建设
  • 汝州网站建设网站建设方案数
  • 跨境电商平台网站建设制作h5用什么软件比较好
  • 网站构建设计思路设计参考网站推荐
  • 两台电脑一台做服务器 网站电商付费推广方式
  • 编写网站 支付宝做爰的最好看的视频的网站
  • 金华企业网站建设富阳seo关键词优化
  • 青岛网上房地产官网查网签苏州seo关键词优化
  • 网站建设行业发展方向企业百度网站怎么做
  • 做西装的网站金融保险网站模板
  • 网站做长连接用手机怎么制作软件
  • 购物网站建设教程全面的客户管理系统
  • 菏泽 兼职做网站阿里云网站建设教程
  • evince魔改记
  • 做内贸的网站小说网站怎么做用户画像
  • Spring AI Advisors API与 Ollama 的结合及实战示例
  • 互联网装修seo网站结构
  • php做自己的网站vue适合什么样的网站开发
  • 界面设计的算法解析
  • 用tornado做网站电商网站前端制作分工
  • 建一家网站多少钱wordpress emlog
  • 1系统分析与设计及 IT 项目管理
  • 企业建设网站目的商标注册45大类明细
  • RHCE : NFS实验1
  • Spring解决循环依赖实际就是用了个递归