You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将三元组作为unordered_set元素?有无替代检查方案?

正确用unordered_set存储三元组的方法及替代方案

一、正确实现unordered_set存储三元组

你原来的代码错误在于unordered_set只能存储单一类型的元素,不能直接声明为unordered_set<long, long, long>,且insert方法仅接受单个元素参数。要实现需求,需要将三个long包装成可哈希、可比较的类型,以下是两种常见实现方式:

1. 使用std::tuple作为元素类型

std::tuple<long, long, long>可以直接打包三个值,但标准库未为tuple提供默认哈希函数,需自定义哈希组合逻辑:

#include <unordered_set>
#include <tuple>
#include <functional>

// 自定义tuple的哈希函数
struct TupleHash {
    template <typename T1, typename T2, typename T3>
    size_t operator()(const std::tuple<T1, T2, T3>& t) const {
        auto h1 = std::hash<T1>{}(std::get<0>(t));
        auto h2 = std::hash<T2>{}(std::get<1>(t));
        auto h3 = std::hash<T3>{}(std::get<2>(t));
        // 组合哈希值(可根据需求调整方式,降低碰撞概率)
        return h1 ^ (h2 << 1) ^ (h3 << 2);
    }
};

int main() {
    // 定义unordered_set,指定tuple类型和自定义哈希
    std::unordered_set<std::tuple<long, long, long>, TupleHash> myset;
    
    // 插入三元组
    myset.insert(std::make_tuple(0, 1, 0));
    // 或使用C++11及以后的列表初始化
    myset.insert({1, 2, 3});
    
    // 检查组合是否存在
    if (myset.count(std::make_tuple(0, 1, 0))) {
        // 存在时的逻辑
    }
    return 0;
}

2. 自定义结构体存储三元组

如果需要更清晰的语义,可以自定义结构体,同时重载==运算符(用于unordered_set判断元素相等)并提供哈希函数:

#include <unordered_set>
#include <functional>

struct Triple {
    long a, b, c;
    
    // 必须重载==,用于元素相等性判断
    bool operator==(const Triple& other) const {
        return a == other.a && b == other.b && c == other.c;
    }
};

// 为Triple自定义哈希函数
struct TripleHash {
    size_t operator()(const Triple& t) const {
        auto h1 = std::hash<long>{}(t.a);
        auto h2 = std::hash<long>{}(t.b);
        auto h3 = std::hash<long>{}(t.c);
        return h1 ^ (h2 << 1) ^ (h3 << 2);
    }
};

int main() {
    std::unordered_set<Triple, TripleHash> myset;
    
    // 插入元素
    myset.insert({0, 1, 0});
    
    // 检查存在性
    if (myset.count({0, 1, 0})) {
        // 存在时的逻辑
    }
    return 0;
}

二、不使用unordered_set的替代方案

如果不想自定义哈希函数,以下几种方法更简便:

1. 使用std::set存储tuple

std::set基于红黑树实现,不需要哈希函数,因为std::tuple默认重载了<运算符,可直接用于排序:

#include <set>
#include <tuple>

int main() {
    std::set<std::tuple<long, long, long>> myset;
    
    myset.insert({0, 1, 0});
    
    // 检查存在性
    if (myset.find({0, 1, 0}) != myset.end()) {
        // 存在时的逻辑
    }
    return 0;
}

注意:std::set的查找、插入时间复杂度为O(log n),而unordered_set是平均O(1),数据量较大时性能会有差异。

2. 将三元组编码为单一数值(数值范围允许时)

如果三个long的取值范围有限,可以将它们编码成一个64位整数(如long long),直接用unordered_set<long long>存储:

#include <unordered_set>

// 编码函数,需确保每个值的范围不会导致溢出
long long encode(long a, long b, long c) {
    // 假设每个值不超过2^20,左移后不会溢出long long
    return (static_cast<long long>(a) << 40) | (static_cast<long long>(b) << 20) | c;
}

int main() {
    std::unordered_set<long long> myset;
    
    myset.insert(encode(0, 1, 0));
    
    if (myset.count(encode(0, 1, 0))) {
        // 存在时的逻辑
    }
    return 0;
}

这种方式无需自定义哈希,性能最优,但要严格控制数值范围,避免编码冲突或溢出。

3. 使用嵌套的无序容器

用unordered_map嵌套存储,结构更直观,无需自定义哈希:

#include <unordered_map>
#include <unordered_set>

int main() {
    std::unordered_map<long, std::unordered_map<long, std::unordered_set<long>>> mymap;
    
    // 插入三元组
    mymap[0][1].insert(0);
    
    // 检查存在性
    if (mymap.count(0) && mymap[0].count(1) && mymap[0][1].count(0)) {
        // 存在时的逻辑
    }
    return 0;
}

这种方式适合需要按前两个值查询第三个值集合的场景,但嵌套结构会增加一点内存开销。


内容的提问来源于stack exchange,提问作者Ryan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 23:55:24