C ++:如何比较几个向量,然后创建一个包含所有向量的所有元素的新排序向量

时间:2011-02-20 16:50:35

标签: c++ sorting vector comparison

更新:关于评论者6502的回答,我有几个可能是愚蠢的问题(如下)。如果有人可以提供帮助,我真的很感激。

1)我理解数据1和数据2是地图,但我不明白 allkeys 的用途。谁能解释一下?

2)我知道:data1 [vector1 [i] .name] = vector1 [i] .value;意味着为感兴趣的地图分配一个值,其中正确的标签是...但我不明白这一点: vector1 [i] .name vector1 [i] .value 。不是“命名”和“重视”两个独立的标签和值向量吗?那么他们在vector1上做了什么?不应该这样读,名[i] 值[i]

谢谢大家。


我已经编写了执行计算的代码。该代码使用其他地方的数据。计算代码很好,但我在操作数据时遇到了麻烦。

数据以矢量集的形式存在。每个集合都有一个标签向量(名称,这些是字符串)和一组相应的值(双精度或整数)。

问题是我需要每个数据集在与其他数据集相同的列中具有相同的名称/标签。这个问题与向量中的数据排序(我知道该怎么做)不同,因为有时某些向量中可能缺少名称/标签。

例如:

数据集1:

vector names1 = Jim,Tom,Mary

向量值1 = 1 2 3

数据集2:

vector names2 = Tom,Mary,Joan

向量值2 = 2 3 4

我想要(伪代码)具有所有可能名称的ONE名称向量。我还希望每个相应的数字向量以相同的方式排序:

vector namesUniversal = Jim,Joan,Mary,Tom

vector valuesUniversal1 = 1 0 3 2

vector valuesUniversal2 = 0 4 3 2

我想要做的是提出一个通用向量,其中包含按字母顺序排序的所有标签/名称,以及所有相应的数值数据也已排序。

有人能告诉我在c ++中是否有一种优雅的方法吗?我想我可以将每个名称向量的每个元素与每个其他名称向量的每个元素进行比较,但这看起来很笨重,我不知道如何将数据放入相应数据向量中的右列。谢谢你的任何建议。

4 个答案:

答案 0 :(得分:4)

您正在寻找的算法通常被命名为“合并”。基本上,您对两个数据集进行排序,然后成对查看数据:如果键是相等的,则处理并输出该对,否则您只处理并推进最小的数据集。

您还必须处理两个列表中的一个在另一个列表之前结束的情况(可以通过使用保证高于您需要处理的任何值的特殊标志值来避免这种情况。)

以下是合并的伪代码

  1. 排序vector1
  2. 排序vector2
  3. 设置index1 = index2 = 0;
  4. 循环直到index1 >= vector1.size()index2 >= vector2.size()(换言之,直到两个向量都耗尽)
  5. 如果index1 == vector1.size()(即已处理vector1),则输出vector2[index2++]
  6. 否则,如果index2 == vector2.size()(即已处理vector2),则输出vector1[index1++]
  7. 否则,如果vector1[index1] == vector2[index2]输出合并数据并同时增加index1index2
  8. 否则,如果vector1[index1] < vector2[index2]输出vector1[index1++]
  9. 否则输出vector2[index2++]
  10. 但是在C ++中,你可以实现一个更容易编写的解决方案,它可能仍然足够快(警告:未经测试的代码!):

    std::map<std::string, int> data1, data2;
    std::set<std::string> allkeys;
    
    for (int i=0,n=vector1.size(); i<n; i++)
    {
        allkeys.insert(vector1[i].name);
        data1[vector1[i].name] = vector1[i].value;
    }
    
    for (int i=0,n=vector2.size(); i<n; i++)
    {
        allkeys.insert(vector2[i].name);
        data2[vector2[i].name] = vector2[i].value;
    }
    
    for (std::set<std::string>::iterator i=allkeys.begin(), e=allkeys.end();
         i!=e; ++i)
    {
       const std::string& key = *i;
       std::cout << key << data1[key] << data2[key] << std::endl;
    }
    

    我们的想法是从名称到值构建两个映射data1data2,同时收集出现在std::set个名为{allkeys的键中的所有键1}}(多次向一组添加相同的名称不起作用)。

    在收集阶段之后,可以迭代此集合以查找已观察到的所有名称,并且可以从data1data2地图(std::map<std::string, int>检索每个名称的值。在查找尚未添加到地图中的名称的值时将返回0。

    从技术上讲,这有点过分(使用三个平衡的树来完成只需要两次排序操作的处理)但是代码较少并且可能是可接受的。

答案 1 :(得分:3)

6502的解决方案乍一看看起来很不错。您应该使用std::merge作为合并部分。

编辑:

我忘了提到现在STL的GNU版本中还有一个multiway_merge扩展STL。它是并行模式的一部分,因此它位于命名空间__gnu_parallel中。如果你需要进行多路合并,很难想出像这样快速或简单的东西。

答案 2 :(得分:1)

我想到的一种快速方法是使用map<pair<string, int>, int>,并使用正确的键将每个值存储在地图中。 (例如(Tom,2)在第一个值集中将位于键(Tom,1)下,值为2) 一旦地图准备好迭代它并构建你想要的任何数据结构(假设地图不够你)。

答案 3 :(得分:0)

我认为你需要改变存储这些数据的方式。 看起来你说每个数字在逻辑上与同一位置的名字相关联:Jim = 1,Mary = 3等。

如果是这样,并且你想坚持某种vector,你可以像这样重做数据结构:

typedef std::pair<std::string, int> NameNumberPair;
typedef std::vector<NameNumberPair> NameNumberVector;

NameNumberVector v1;

您需要编写自己的operator<,它根据基础名称的排序顺序返回。但是,正如Nawaz指出的那样,map将是表示数据相关性质的更好方式。