C++ 在c++;
有人能提出一种快速的方法来获得向量中每个元素的秩吗。 我不需要对向量进行排序,只要对向量进行排序,就可以得到每个元素的索引 例如:{40,20,10,30} 应该给出{3,1,0,2}C++ 在c++;,c++,c++11,C++,C++11,有人能提出一种快速的方法来获得向量中每个元素的秩吗。 我不需要对向量进行排序,只要对向量进行排序,就可以得到每个元素的索引 例如:{40,20,10,30} 应该给出{3,1,0,2} 我是否能够获得加速,因为我实际上不必对数据进行适当排序?同样的排序下限证明也适用于这里。如果没有其他信息(密钥分发等),则下限为n log(n),您也可以进行排序。从形式上讲,任何更低的值都允许您将排列压缩到下面 话虽如此,问题在于如何对指数进行排序。看。我可以想出两种方法:(但我不认为它们会更快) 将对放入地
我是否能够获得加速,因为我实际上不必对数据进行适当排序?同样的排序下限证明也适用于这里。如果没有其他信息(密钥分发等),则下限为n log(n),您也可以进行排序。从形式上讲,任何更低的值都允许您将排列压缩到下面
话虽如此,问题在于如何对指数进行排序。看。我可以想出两种方法:(但我不认为它们会更快)
对放入地图中对于数字而言,对数组本身进行排序并不比对索引进行排序困难——您将构建一个索引集,并按照原始值对其进行排序。第一种方法是复制数组并对其进行排序。然后遍历原始数组,对每个项执行二进制搜索以确定秩。在此遍历过程中,生成所需的序列。在这个方法中,你取O(n)作为副本,加上O(n lgn)作为排序,最后O(n lgn)作为产生列组序列 另一种方法是将所有项目插入二叉搜索树(一种平衡的搜索树,如avl或红黑)。这需要O(n lgn)。二叉树必须支持“秩扩展”;也就是说,每个子树的大小必须存储在节点中。这些树可以导出操作
position(key)
,该操作返回key
的等级
然后,遍历数组,并为每个条目调用位置(array[i])
。在此过程中,您将生成与数组平行的秩序列。这需要O(n lgn)
我认为这种方法的优点是,复制到成对数组中,然后对其进行排序,或者简单地对数组的副本进行排序,然后通过在复制的数组中进行二进制搜索来确定秩,这样可以避免从已排序的成对数组到秩序列的额外副本
增加和更正:
根据@xiaotian peiI的回答,我认为在按键排序的确定平衡二叉搜索树(avl或红黑)中插入对(键、索引)会更好;这需要O(n lgn)。然后遍历二叉树以提取索引,这需要O(n)。最后你释放了这棵树,什么需要O(n)。所以总数是O(n lgn)+O(n)+O(n)
根据规模和复杂性的不同,可能更有效:使用一堆对(键、索引)并从中连续提取以构建列组序列
而且速度可能更快,占用的空间肯定更少:Jarod42发布的算法,我认为也是O(n)+O(n lg n)+O(n),但这将使缓存获益更多
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;
}
模板
标准::向量计算顺序(常数标准::向量&v)
{
向量指数(v.size());
std::iota(index.begin()、index.end()、0u);
排序(index.begin(),index.end(),[&](int-lhs,int-rhs){
返回v[lhs]
[我认为]排序向量是最快的方法,这个例子不应该给出{2,1,3,0}?不,很明显,最低的值(10)有最低的索引(0)A[]={40,20,10,30},I[]={2,1,3,0},A[I[]={A[2],A[1],A[3],A[0]={10,20,30,40}。Puppy是write@rcgldr你误解了我不想要原始索引,我想要他们的新指数,假设他们被分类了这是一个很好的答案,但我知道你不能超过nlog(n)下限,我所说的加速是在这一范围内,但在复杂的细节中。。像常数因子或something@VikashB请参阅更新。我不得不说,在这方面,你的问题是一个重复的问题,不是吗?不是真的,因为常数的因素将是非常不同的,你不能完全在C++中使用NoPy。为什么你不能使用NUMPY?code>numpy.argsort(foo)应该适用于您的示例。我的钱是,这也给出了最好的常数。@ AmiTavory:因为NUMPY不是C++。是Python
g++
将不会接受numpy.argsort(foo)
。不,它不会打败仅仅对向量进行排序。完美,正是我想要的,第二种方法很棒,我以前没有听说过秩扩展。下面由Jarod42提供的答案更有效。您可以根据数组对索引进行排序,然后使用排序后的索引进行单次传递(O(n)),以创建原始帖子中所需索引的数组(Jarod42答案中的vector res)。@rcgldr:是!这是一个非常漂亮的解决方案。我编辑了答案,并解释了第三种方法,我认为这种方法更有效。据我所知,Jarod42方案需要O(n)来初始化索引(iota调用),然后O(n lg n)来排序,最后O(n)来提取列组;这将需要O(n)+O(nlgn)+O(n)与O(nlgn)+O(n)@Irleon-我不明白什么方法需要O(nlgn)+O(n)。对于二叉树方法,必须在树中插入元素(如果使用对,则创建对),然后遍历树。树操作要比排序所使用的索引和“源”索引转换为“目的地”索引花费更多的时间。我错了,因为我忘记考虑树的释放。因此,在二叉搜索树中有n对插入;什么需要O(n lg n)。然后按顺序遍历二叉树,在遍历过程中,将索引复制到se