C++ c++;通过使用旧向量预排序改进向量排序
我有一个向量对,它的类型如下C++ c++;通过使用旧向量预排序改进向量排序,c++,sorting,vector,C++,Sorting,Vector,我有一个向量对,它的类型如下 typedef std::pair<double, int> myPairType; typedef std::vector<myPairType> myVectorType; myVectorType myVector; 我的程序有许多时间步,在double值中略有变化,每一个时间步我都用std::sort对这个向量进行如下排序 0.5245 3 0.5434 2 0.6594 1 0.8431 4 现在的想法是以某种方式使用上一个时间
typedef std::pair<double, int> myPairType;
typedef std::vector<myPairType> myVectorType;
myVectorType myVector;
我的程序有许多时间步,在double
值中略有变化,每一个时间步我都用std::sort
对这个向量进行如下排序
0.5245 3
0.5434 2
0.6594 1
0.8431 4
现在的想法是以某种方式使用上一个时间步骤中的向量(“旧向量,已排序”)对当前向量(新向量,尚未排序)进行预排序。并使用插入排序或tim排序对预排序向量的“其余”进行排序
这有可能吗?我找不到一个函数将成对的“新”向量按一个部分(即int
部分)排序。
如果可能的话,这会比排序整个未排序的“新”向量更快吗
谢谢你给我指明了正确的方向
蒂奥姆
更新
首先,感谢所有的建议和代码示例。我将看看它们中的每一个,并做一些基准测试,如果它们能加快这个过程
因为这里有一些关于向量的问题,我将尝试更详细地解释我想要实现的目标
正如我所说,如果时间步1
到n
,我有一个数字。对于每个时间步,我有一个double
数据值的向量,包含大约260000个元素
在每一个时间步骤中,我都会向这个向量添加一个索引,这将产生成对的向量
。请参阅下面的代码片段
typedef typename myVectorType::iterator myVectorTypeIterator; // iterator for myVector
std::vector<double> vectorData; // holds the double data values
myVectorType myVector(vectorData.size()); // vector of pairs <double, int>
myVectorTypeIterator myVectorIter = myVector.begin();
// generating of the index
for (int i = 0; i < vectorData.size(); ++i) {
myVectorIter->first = vectorData[i];
myVectorIter->second = i;
++myVectorIter;
}
std::sort(myVector.begin(), myVector.end() );
排序之后呢
0.000102207 23836
0.000107378 256594
0.00010781 51300
0.000109315 95454
0.000109792 102172
...
因此,我在下一个时间步骤j
中,这是我的vectorOld
,我想取索引为23836
的“new”元素“myVector
并将其放在presortedVector
的第一位,索引为256594
的元素应该是presortedVector
中的第二个元素,依此类推。但是元素必须保持其原始索引。因此256594
将不是索引0
,而是presortedVector
中的元素0,仍然具有索引256594
我希望这能更好地解释我的计划。使用排序向量可能会导致更多比较(只是为了找到匹配项) 您似乎正在寻找的是一个自订购容器 您可以使用集合(并在修改时删除/重新插入)
或者,您可以使用Boost Multi Index,它提供了更多的便利(例如,使用一个结构而不是一对)我不知道这是否比对整个未排序的“新”向量进行排序更快。这将取决于数据 但这将根据旧向量的顺序创建新向量的排序副本:
myVectorType getSorted(const myVectorType& unsorted, const myVectorType& old) {
myVectorType sorted(unsorted.size());
auto matching_value
= [&unsorted](const myPairType& value)
{ return unsorted[value.second - 1]; };
std::transform(old.begin(), old.end(), sorted.begin(), matching_value);
return sorted;
}
然后需要“完成”对该向量的排序。我不知道这比从头开始排序要快多少(如果有的话)
首先,扫描序列以找到比前一个元素小的第一个元素(循环或C++11)。这是未排序部分的开始。在剩余部分上使用,然后将两半合并为
模板
void sort\u new\u元素(RandomIt first,RandomIt last,comp comp比较)
{
RandomIt mid=std::在(第一个、最后一个、comp)之前进行排序;
标准::排序(中间、最后、复合);
标准:就地合并(第一、中间、最后、合并);
}
这应该比不加区分地对整个序列进行排序更有效,只要前面的预排序序列明显大于未排序的部分。您可以按照旧的顺序创建新的向量,然后使用(几乎)具有良好复杂性的算法用于恢复顺序的已排序输入 下面我举了一个例子来说明它是如何工作的,使用as
restore\u order
:
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
using namespace std;
typedef std::pair<double, int> myPairType;
typedef std::vector<myPairType> myVectorType;
void outputMV(const myVectorType& vect, std::ostream& out)
{
for(const auto& element : vect)
out << element.first << " " << element.second << '\n';
}
//https://stackoverflow.com/a/28813905/1133179
template<class RandomIt, class Compare>
void restore_order(RandomIt first, RandomIt last, Compare comp)
{
RandomIt mid = std::is_sorted_until(first, last, comp);
std::sort(mid, last, comp);
std::inplace_merge(first, mid, last, comp);
}
int main() {
myVectorType myVector = {{3.5,0},{1.4,1},{2.5,2},{1.0,3}};
myVectorType mv2 = {{3.6,0},{1.35,1},{2.6,2},{1.36,3}};
auto comparer = [] (const auto& lhs, const auto& rhs) { return lhs.first < rhs.first;};
// make sure we didn't mess with the initial indexing
int i = 0;
for(auto& element : myVector) element.second = i++;
i = 0;
for(auto& element : mv2) element.second = i++;
//sort the initial vector
std::sort(myVector.begin(), myVector.end(), comparer);
outputMV(myVector, cout);
// this will replace each element of myVector with a corresponding
// value from mv2 using the old sorted order
std::for_each(myVector.begin(), myVector.end(),
[mv2] (auto& el) {el = mv2[el.second];}
);
// restore order in case it was different for the new vector
restore_order(myVector.begin(), myVector.end(), comparer);
outputMV(myVector, cout);
return 0;
}
#包括
#include,虽然有效,但仍不完美
它可以通过受气泡排序启发的方法获得更好的性能。例如,如果current
和next
元素之间的顺序错误,则迭代每个元素,递归地交换current
和next
。然而,在订单变化的程度上有一个赌注-如果订单变化不大,您将保持在O(2n)
附近,如果变化,您将上升到O(n^2)
我认为最好的办法是实施。具有最佳情况(已排序的输入)O(n)
,以及最差情况O(n log n)
std::vector不适合插入,因此您需要排序多少个值?是否附加新值?另一种方法是使用std::set,但您应该对代码进行基准测试。如果值的数量不太大,那么使用向量可能比使用std::set更快。我在向量中有大约260000对。对于所提到的std:set
,这是否太多了?啊,是的,没有附加新值。不清楚“旧向量”是什么意思。你有两个相似的向量吗,一个排序,另一个几乎排序?或者你只需要一个向量,它最初被排序,然后对它应用少量的局部更改?我有很多时间步。每个时间步的数据点数量与双精度值相同(约260000)。现在,在每个时间步中,我将数据点加载到向量的double
部分,生成索引(int
向量部分),并使用std::sort()
对该向量进行排序。现在的想法是使用时间步0(vector0)中已排序的向量对时间步1(vector1)中的向量进行“预排序”,方法是使用vector0的索引对vector1重新排序,并使用tim sort之类的排序函数对向量的“其余”进行排序。我希望这能让它更清楚。嗨,我试着把你的函数放到我的代码中去做一些基准测试。但是,它只适用于1个时间步。我现在有了类似于if(timestep>=1){vector\u presorted=getSorted(vector\u pair\u new,vector\u pair\u old);std::sort(vector\u presorted.begin(),vector\u presorted.end());v
myVectorType getSorted(const myVectorType& unsorted, const myVectorType& old) {
myVectorType sorted(unsorted.size());
auto matching_value
= [&unsorted](const myPairType& value)
{ return unsorted[value.second - 1]; };
std::transform(old.begin(), old.end(), sorted.begin(), matching_value);
return sorted;
}
template<class RandomIt, class Compare>
void sort_new_elements(RandomIt first, RandomIt last, Compare comp)
{
RandomIt mid = std::is_sorted_until(first, last, comp);
std::sort(mid, last, comp);
std::inplace_merge(first, mid, last, comp);
}
#include <iostream>
#include <algorithm>
#include <vector>
#include <utility>
using namespace std;
typedef std::pair<double, int> myPairType;
typedef std::vector<myPairType> myVectorType;
void outputMV(const myVectorType& vect, std::ostream& out)
{
for(const auto& element : vect)
out << element.first << " " << element.second << '\n';
}
//https://stackoverflow.com/a/28813905/1133179
template<class RandomIt, class Compare>
void restore_order(RandomIt first, RandomIt last, Compare comp)
{
RandomIt mid = std::is_sorted_until(first, last, comp);
std::sort(mid, last, comp);
std::inplace_merge(first, mid, last, comp);
}
int main() {
myVectorType myVector = {{3.5,0},{1.4,1},{2.5,2},{1.0,3}};
myVectorType mv2 = {{3.6,0},{1.35,1},{2.6,2},{1.36,3}};
auto comparer = [] (const auto& lhs, const auto& rhs) { return lhs.first < rhs.first;};
// make sure we didn't mess with the initial indexing
int i = 0;
for(auto& element : myVector) element.second = i++;
i = 0;
for(auto& element : mv2) element.second = i++;
//sort the initial vector
std::sort(myVector.begin(), myVector.end(), comparer);
outputMV(myVector, cout);
// this will replace each element of myVector with a corresponding
// value from mv2 using the old sorted order
std::for_each(myVector.begin(), myVector.end(),
[mv2] (auto& el) {el = mv2[el.second];}
);
// restore order in case it was different for the new vector
restore_order(myVector.begin(), myVector.end(), comparer);
outputMV(myVector, cout);
return 0;
}