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;
}