映射,对向量或两个向量..

Map, pair-vector or two vectors...?

本文关键字:向量 两个 映射      更新时间:2023-10-16

我通读了一些帖子和"wiki",但仍然无法决定哪种方法适合我的问题。

我创建了一个名为Sample的类,它包含一定数量的化合物(假设这是另一个类Nuclide),具有一定的相对数量(双倍)。

因此,类似(伪):

class Sample {
    map<Nuclide, double>;
}

如果我在样本中有核素Ba-133Co-60Cs-137,我将不得不在代码中准确地使用这些名称来访问地图中的这些核素。但是,我唯一需要做的就是遍历映射以执行计算(它们是什么核素不感兴趣),因此,我将使用 for- 循环。我想在不注意键名的情况下进行迭代,因此,我需要为地图使用迭代器,对吗?

另一种选择是vector<pair<Nuclide, double> >

class Sample {
    vector<pair<Nuclide, double> >;
}

或只是两个独立的向量

Class Sample {
    vector<Nuclide>;
    vector<double>;
}

而在最后一个选项中,核素与其数量之间的联系将是"元信息",仅由相应载体中的位置给出。

由于我缺乏丰富的经验,我会善意地询问选择哪种方法的建议。我希望快速轻松地迭代所有可用的化合物,同时保持相应键和值的逻辑结构。

PS.:样品中的组合数量可能非常低(1到5)!PPS.:最后一个选项是否可以通过一些const语句进行修改,以防止更改,从而保持正确的顺序?

如果迭代需要快速,你不希望std::map<...>:它的迭代是一棵树散步,很快就会变坏。 只有当你对序列有很多突变并且你需要按键排序的序列时,std::map<...>才是合理的。如果你有突变,但你不在乎顺序std::unordered_map<...>通常是更好的选择。不过,这两种地图都假设您正在按键查找内容。从你的描述来看,我真的不认为是这样。

std::vector<...>迭代速度很快。不过,它不适合查找。如果你保持它的顺序,你可以使用std::lower_bound()来做一个类似std::map<...>的查找(即,复杂性也是O(log n)的),但是保持它排序的努力可能会使这个选项过于昂贵。但是,它是将一堆迭代对象放在一起的理想容器。

你想要一个std::vector<std::pair<...>>还是两个std::vector<...>取决于你如何访问元素:如果元素的两个部分绑定在一起访问,你需要一个std::vector<std::pair<...>>,因为它保留一起访问的数据。另一方面,如果您通常只访问两个组件中的一个,则使用两个单独的std::vector<...>将使迭代更快,因为更多的迭代元素适合缓存行,特别是如果它们像 double s 一样相当小。

无论如何,我建议不要将外部结构暴露给外部世界,而是提供一个接口,让您稍后更改底层表示。也就是说,为了实现最大的灵活性,您不希望将表示形式烘焙到所有代码中。例如,如果您使用访问器函数对象(BGL 方面的属性映射或 Eric Niebler 的范围提案中的投影)来访问基于迭代器的元素,而不是访问元素,您可以更改内部布局而无需接触任何算法(您需要重新编译代码, 虽然):

// version using std::vector<std::pair<Nuclide, double> >
// - it would just use std::vector<std::pair<Nuclide, double>::iterator as iterator
auto nuclide_projection = [](Sample::key& key) -> Nuclide& {
    return key.first;
}
auto value_projecton = [](Sample::key& key) -> double {
    return key.second;
}
// version using two std::vectors:
// - it would use an iterator interface to an integer, yielding a std::size_t for *it
struct nuclide_projector {
    std::vector<Nuclide>& nuclides;
    auto operator()(std::size_t index) -> Nuclide& { return nuclides[index]; }
};
constexpr nuclide_projector nuclide_projection;
struct value_projector {
    std::vector<double>& values;
    auto operator()(std::size_t index) -> double& { return values[index]; }
};
constexpr value_projector value_projection;

对于一对就地,例如,算法只是在它们上运行并打印它们,如下所示:

template <typename Iterator>
void print(std::ostream& out, Iterator begin, Iterator end) {
    for (; begin != end; ++begin) {
         out << "nuclide=" << nuclide_projection(*begin) << ' '
             << "value=" << value_projection(*begin) << 'n';
    }
}

这两种表示形式完全不同,但访问它们的算法是完全独立的。这样也很容易尝试不同的表示:只需要更改表示和访问它的算法的粘合剂。