在c ++

时间:2015-06-06 16:18:21

标签: c++ c++11

任何人都可以建议快速获取向量中每个元素的等级。 我不需要对矢量进行排序,但只有在矢量被排序后才能得到每个元素的索引

代表:{40,20,10,30} 应该给{3,1,0,2}

我是否可以获得加速,因为我实际上不必对数据进行排序?

5 个答案:

答案 0 :(得分:6)

此处适用于排序下限的完全相同的证明。没有其他信息(密钥分发等),它是 n log(n)的下限,你也可以排序。正式地说,任何较低的东西都允许你压缩Kolmogorov complexity以下的排列。

话虽如此,还有如何对指数进行排序的问题。请参阅here

答案 1 :(得分:3)

您可以使用以下内容:

template <typename T>
std::vector<std::size_t> compute_order(const std::vector<T>& v)
{
    std::vector<std::size_t> indices(v.size());
    std::iota(indices.begin(), indices.end(), 0u);
    std::sort(indices.begin(), indices.end(), [&](int lhs, int rhs) {
        return v[lhs] < v[rhs];
    });
    std::vector<std::size_t> res(v.size());
    for (std::size_t i = 0; i != indices.size(); ++i) {
        res[indices[i]] = i;
    }
    return res;
}

Live example

答案 2 :(得分:2)

我可以想到两种方式:(但我认为它们不会更快)

  1. <value, index>对放入地图
  2. 将索引放在另一个向量中,使用适当的比较函数对该向量进行排序

答案 3 :(得分:1)

第一种方法是对数组进行复制并对其进行排序。然后,您遍历原始数组,并在每个项目上执行二进制搜索以确定排名。在此遍历期间,您将生成所需的序列。有了这个方法,你需要O(n)作为副本,加上O(n lg n)进行排序,最后是O(n lg n)来产生排序。

另一种方法是将所有项目插入二叉搜索树(平衡的一个,如avl或红黑)。这需要O(n lg n)。您的二叉树必须支持&#34;等级扩展&#34 ;;也就是说,每个子树的大小必须存储在节点中。这些树可以导出操作position(key),返回key的等级。

然后,您遍历您的数组,并为您调用position(array[i])的每个条目。在此过程中,您将生成与阵列平行的等级序列。这需要O(n lg n)。

我认为这种方法的优点是复制到一对数组然后对其进行排序或者只是对数组的副本进行排序然后通过在复制的数组中使用二进制搜索进行搜索来确定排名,就是你避免从排序的数组对中的额外副本到排名序列。

添加并更正:

根据@ xiaotian-peiI的回答,我认为简单地将对(密钥,索引)插入到按键排序的确定性平衡二叉搜索树(avl或red-black)中会更好;需要O(n lg n)。然后遍历二叉树以便提取索引,取O(n)。最后你释放了树,O(n)。所以总数将是O(n lg n)+ O(n)+ O(n)

根据规模而不是相同的复杂性,可能更有效:使用一堆对(密钥,索引)并连续从中提取以构建排名顺序。

并且很可能更快且更少占用空间:Jarod42发布的算法,我认为O(n)+ O(n lg n)+ O(n)也是如此,但这会获得更多的缓存

答案 4 :(得分:0)

对于数字的情况,排序数组本身并不比排序索引更难 - 您将构建索引集并按原始值排序。