检查向量是否已排序的最佳算法

时间:2008-11-04 14:15:10

标签: c++ algorithm optimization vector

检查std::vector是否排序的最佳方法是什么?有没有比检查v[i]<=v[i+1]的循环更快的东西?迭代器更快/更清洁吗?或者每次只调用sort实际上更好(虽然“v已经排序”的情况很常见)?

我们可以安全地假设该向量仅包含POD,通常是float s,有时是double s和int s。

矢量的大小非常重要(通常是几千个项目),但不是极端的(不是千兆字节大小)。

  • 在某些情况下,我们会立即对矢量进行排序,但是还有其他情况我们没有(这是我们算法的错误情况)。
  • 我们已尽可能使用“IsSorted”标志。

13 个答案:

答案 0 :(得分:28)

  

是否有比循环更快的东西   检查v [i]&lt; = v [i + 1]?

没有

如果这是您希望经常检查的内容,您可能希望创建一个包装类,该类保留一个“sorted”标志,该标志以False开头,每当添加一个项目时设置为False,并添加一个成员函数sort( )在排序后将标志设置为True。

答案 1 :(得分:20)

最好的方法是使用std::is_sorted

is_sorted(v.begin(), v.end())

: - )

答案 2 :(得分:16)

考虑多个Cpu核心<​​/ strong>

这取决于您的平台和向量中的项目数。你必须做基准测试才能找到最好的东西。

无法回答:是否有比循环检查v [i]&lt; = v [i + 1]更快的东西?
用:否。

因为...计算机现在有几天有多个cpus / cores /超线程。因此,通过将检查工作分成多个线程来利用计算机中的并行性可能要快得多,因此每个cpu可以并行检查小范围。

最好通过库函数来实现,而不是自己实现。新版本的库将利用并行性。所以,如果你选择std :: sort,你可能会发现当你构建新的STL实现时,他们会为你并行执行操作,而不必担心它。我不知道是否有现成的STL版本可以做到这一点,但是值得坚持使用库函数,这样当你升级到这样的版本时,这个优化适合你而不需要做任何修改

答案 3 :(得分:12)

std::adjacent_find(v.begin(), v.end(), std::greater<type>()) == v.end()

答案 4 :(得分:6)

当然我不知道你的问题领域,所以如果我所说的不相关,请忽略我,但在我看来,如果我要求一个集合总是在我访问它时被排序,一个自然未分类像vector<T>这样的集合可能不是最佳选择。

答案 5 :(得分:5)

  

有没有比循环检查v [i]&lt; = v [i + 1]更快的东西?

您需要检查任何值以查看它是否已排序,因此它不会比O(n)快得多,除非您在改变向量或使用已经排序的数据结构时自己跟踪更改。 / p>

  

或者每次调用sort实际上更好(虽然“v已经排序”的情况很常见)?

请记住,当列表已经排序(并且枢轴选择不正确)时,会发生快速排序最坏情况行为。为了避免这种行为,您可能需要检查std :: stable_sort作为替换。

答案 6 :(得分:2)

如果您希望列表非常接近排序,那么尝试修改insertion sort可能会有所帮助。如果列表已经排序,它只会执行一次并告诉您。如果列表几乎排序,它将很快排序。如果列表未排序,则在交换一定数量后切换到排序并切换到快速排序(或stable_sort)。

答案 7 :(得分:2)

C ++ - 11在&lt; algorithm&gt;中包含is_sorted。

答案 8 :(得分:1)

  

有没有比循环检查v [i]&lt; = v [i + 1]更快的东西?

没有

但是,如果您要执行检查以决定是否对矢量进行排序,那么最好总是排序如果您使用正确的排序算法,即std :: stable_sort而不是std :: sort。

答案 9 :(得分:0)

为了检查分类,您必须检查每个项目。所以v [i]&lt; = v [i + 1]是最快的检查。

答案 10 :(得分:0)

正如其他人所指出的,确定排序状态的谓词是O(n)。但是,从你提到的排序标志,我有点想知道你是否不想要这样的东西:

我们的应用程序的基础库包括一个可以查询成员资格的容器类。这是一个简短的草图:

class ObjList {
public:
    ObjList() {};
    ~ObjList() {};

    bool isMember(const Item *);
    void add(const Item *, bool sort = false);

private:

    unsigned int last_sorted_d;

    bool sorted_d;
    unsigned int count_d;
    Item *store_d;
};

isMember()在元素的排序范围上使用二进制搜索,然后在排序范围之后对项目进行线性搜索。根据程序员的选择,插入可以触发某种项目,也可以不触发。例如,如果您知道您将在紧密循环中添加数千个项目,请不要在最终插入之前进行排序。

上面只是一个草图,商店比指针数组更复杂,但你明白了。

答案 11 :(得分:0)

如果您在插入项目时使用二进制搜索来查找插入点,那么它永远不会被订购。

答案 12 :(得分:0)

如果您的C ++标准库实现包含算法is_sorted(),那么它是最佳选择。