【问题标题】:What's a good way of *temporarily* sorting a vector?什么是*临时*对向量进行排序的好方法?
【发布时间】:2011-01-19 17:49:27
【问题描述】:

我有一个 std::vector,我需要为某些操作按选定的算法进行排序,但在其余时间保持其原始状态(例如,在输入时排序的项目)。

显然我可以使用 std::copy 创建一个临时向量并对其进行排序,但我想知道是否有更好的方法,可能是通过为输入的项目加上时间戳。

干杯

【问题讨论】:

  • 为什么?排序是O(N log N),更不用说常数因子了;假设 POD 元素,复制直接是 N * sizeof(T) 内存写入。另外,您可以轻松地从基准测试中排除复制时间。
  • 假设 POD 元素,复制是恒定时间(提示:想想 memcpy),而且速度相当快。
  • 复制不是固定时间,@Stingray。这是 O(N)。
  • @Rob:是的,你是对的。忘了废话还是要一个字一个字地通过 CPU!

标签: c++ sorting vector temporary


【解决方案1】:

您可以创建一个 std::vector 来保存第一个向量的所有索引。然后,您可以根据需要对索引向量进行排序。这应该很快,最重要的是,这并不意味着您必须复制第一个向量(这可能更昂贵!)。

【讨论】:

  • +1 表示最快的手指,发布的答案大致相同。
  • 我会使用老式 malloc 的指针数组并调用 qsort,但这也可以。
  • 我敢打赌,生成索引向量比复制原始向量需要更长的时间!
  • 我会接受这个赌注,@Stingray。我要提供我们存储在向量中的类。 (特别是,我可以定义复制构造函数和赋值运算符。)我还可以选择我们要存储的数量。 (很多!)
  • 听起来不错,你能描述一下怎么做吗?代码示例会有所帮助。
【解决方案2】:

任何给定的向量在任何时候都将最多以一种方式排序。

有两种选择:

复制到一个临时向量并根据需要对其进行排序。除非向量非常大并且您的空间有限,否则这几乎肯定是最好的方法。即使您担心性能,制作副本的成本也将小于排序成本,如果复制成本很高,则排序将比复制慢很多。

或者,您可以保留某种方式(您提到的时间戳?)能够将向量排序回原始顺序。这会很慢,因为您只想在向量非常大的情况下执行此操作,但如果您无法制作临时向量,这是唯一的方法。

【讨论】:

  • 如果不是指针向量,复制可能会很昂贵,还取决于复制 ctor 的实现方式。
  • @Binary Worrier:我认为大卫的观点是,向量上的排序操作在移动元素时会执行一堆副本。如果排序是 O(n log n),则添加 O(n) 复制操作最初不会改变整体时间复杂度。
  • 如果复制成本很高,那么排序就更贵了。您如何期望在不将每个元素复制到新位置的情况下获得排序的向量? (实际上,复制构造函数可能比赋值运算符昂贵得多,在这种情况下,正确的做法是修复复制构造函数。我不认为复制构造函数应该贵得多。 )
  • 通过 a) 对指针向量进行排序或 b) 通过对映射到原始向量中对象位置的整数数组/向量进行排序来间接排序向量。禁止复制。
【解决方案3】:

无论您要排序的项目是什么,都可以将其包装在具有多个排序字段的结构中。

struct someThing
{
    int sortOrder1;
    int sortOrder2;
    ...
    int sortOrderN;
    //payload data object here
} //note: this code may have some sytax errors (I haven't actually tried compiling this ;), but hope the idea is clear

(或者可能将排序顺序添加到基本结构本身?)

然后当您需要时可以计算不同的排序顺序,并根据您需要的排序顺序重新排序您的列表。

【讨论】:

    【解决方案4】:

    如果您不介意一点点 Boost,您可以使用 MultiIndex 库。请参阅我的this answer,您可以在其中找到一些示例代码。

    基本上,它允许您保留相同数据的多个“视图”,每个视图具有不同的顺序。在您的情况下,您将能够保留一个“序列”视图,其中数据按插入顺序排列(如矢量)和一个“排序”视图,其中数据根据某些标准(如地图)进行排序.

    【讨论】:

      【解决方案5】:

      我建议在每个vector 中存储指向原始数据的智能指针。 std::vector 允许您提供不同的排序方法。此外,使用智能指针,当所有对该项目的引用都被删除时,它们将被自动销毁。

      【讨论】:

        【解决方案6】:

        您可以创建另一个向量来存储索引。代码如下:

        #include <iostream>
        #include <algorithm>
        #include <vector>
        using namespace std;
        
        int main()
        {
            vector<int> numbers = {50,30,20,10,40};
            vector<int> indexOfNumbers;
            
            for(int i = 0; i < numbers.size(); i++)
            {
                indexOfNumbers.push_back(i); 
            }
            // Now, indexOfNumbers = [0,1,2,3,4]
        
            std::sort(
                indexOfNumbers.begin(), indexOfNumbers.end(), 
                [numbers](int leftIndex, int rightIndex) 
                { 
                    return numbers[leftIndex] < numbers[rightIndex]; // sort in ascending order
                }
            );
            // After sorting, indexOfNumbers = [3, 2, 1, 4, 0]
        
            // Access the sorted elements
            cout << "Accessing the sorted elements : ";
            for(int i = 0; i < numbers.size(); i++)
            {
                cout << numbers[indexOfNumbers[i]] << " ";
            }
            // prints numbers in sorted order i.e. [10,20,30,40,50]
           return 0;
        }
        

        来源:根据 Tyrer 的回答(https://stackoverflow.com/a/47537314)稍作修改

        【讨论】:

          猜你喜欢
          • 2018-05-12
          • 1970-01-01
          • 1970-01-01
          • 2010-11-05
          • 2010-11-07
          • 2015-09-16
          相关资源
          最近更新 更多