如何降低排序的时间复杂度?

Posted

技术标签:

【中文标题】如何降低排序的时间复杂度?【英文标题】:How to decrease time complexity of sorting? 【发布时间】:2012-08-13 17:31:10 【问题描述】:

我已经编写了这个排序代码,它运行得很好。我想知道如何降低它的时间复杂度。

#include <iostream>

using namespace std;

void sort(int a[], int n)

    int min, temp;
    for(int i=0;i<n-1;i++)
    
        min=i;
        for(int j=i+1;j<n;j++)
        
            if(a[min]>a[j])
            
                min=j;
            
        
        temp=a[i];
        a[i]=a[min];
        a[min]=temp;
    
    for(int i=0;i<n;i++)
    
        cout<<a[i]<<endl;
    

int main()
    
    int n;
    cin>>n;
    int arr[n];
    for(int i=0;i<n;i++)
    
        cin>>arr[i];
    
    sort(arr,n);
    return 0;

如果没有其他方法可以更改它,那么我是否必须更改算法?如果是,请推荐一个算法?

谢谢。

【问题讨论】:

这是作业吗?你有没有描述过你日常工作的复杂性? 自己做。这就是为什么我没有要求代码,只要求算法名称,因为它类似于作业问题.m:) @MichaelBurr 只是想知道答案是否重要? @Артём Царионов:我认为人们经常以不同的方式回答基于家庭作业的问题。例如,避免简单地“给出答案”或将答案更多地定位于基本面。至于表征当前例程的复杂性 - 在您了解当前情况(至少在某种程度上)之前,您如何知道您是否已经改进了一些事情? @MichaelBurr 好点子,我一直不明白为什么人们关心它是否是家庭作业 【参考方案1】:

您似乎使用了某种选择排序,这种方法众所周知很慢。 IRL 应用程序通常使用quicksortmerge-sort(不是后者)。

我建议你也这样做(假设这是出于教育目的)。

否则,使用&lt;algorithm&gt; 中定义的std::sort

另外,请注意您的代码不是标准的:

cin>>n;
int arr[n];

C++ 不支持 VLA。你最好改用std::vector。如果您使用 C++,请不要编写 C 代码。

【讨论】:

VLA 是?变长数组? @LuchianGrigore- std::sort 使用哪种算法对数组进行排序? @PrakharMohan idk 如果它被强制执行。来自链接:Complexity Approximately N*logN comparisons on average (where N is last-first). In the worst case, up to N^2, depending on specific sorting algorithm used by library implementation. 来自"depending" 我认为该标准并未强制执行特定算法,而是遵守复杂性要求的算法。 后一优先是什么意思?这就是我想知道的?该库使用哪种算法?正是我的问题。 :) @PrakharMohan:“STL 的 list::sort() 使用了哪种排序算法?” - ***.com/questions/1717773/…【参考方案2】:

您的算法是选择排序,一种O(n^2) 算法:如果输入大小在n 中线性增长,则运行时间与n 的二次函数成正比。基于任意输入(即没有关于输入的先验知识)的比较排序的最小时间复杂度为O(n log n)。 STL 函数std::sort 提供了这种保证。

#include <algorithm>
#include <vector>

int main()

    int n;
    cin>>n;
    std::vector<int> arr;
    arr.resize(n);

    for(int i=0;i<n; ++i) // ++i rather than i++ is a good habit to get into
    
        cin>>arr[i];
    

    // O(N log N) complexity
    std::sort(arr.begin(), arr.end());

    return 0;

对于小的输入,选择排序(或插入排序)有时可以足够快。您也可以在 C++11 中将其编码为几行代码(它使用 lambda 表达式)

#include <algorithm>
#include <iterator>

template<class ForwardIterator>
void selection_sort(ForwardIterator first, ForwardIterator last)

        std::for_each(first, last, [](ForwardIterator it)          // your outer loop
                auto const selection = std::min_element(it, last);  // your inner loop
                std::iter_swap(selection, it);                      // your swap code
        );


// call on your vector
selection_sort(arr.begin(), arr.end());

从这段代码中,选择排序的工作原理也一目了然:重复地在数组的剩余部分中找到最小元素,并将其交换到位。它应该等同于您自己的代码,但我希望您同意它更容易理解(也就是说,一旦您了解了 STL)。

【讨论】:

您好!我不想用这个评论冒犯你,但是:1)如果这是出于教育目的,你并没有通过提供完整的解决方案来帮助他。 2) 代码无效,因为 C++ 不支持变长数组。 reserve 应该是resize,否则你有未定义的行为。此外,您对 std::sort 的调用是为数组编写的,但现在您使用的是向量。【参考方案3】:

您正在使用Selection sort 对数组进行排序。该算法的运行时间 id O(n^2)。您可以使用Merge sortHeap Sort对运行时间为O(nlog(n))的排序。 您还可以使用Intro Sort,它使用一个非常巧妙的技巧将QuickSort's 最坏情况下推到 O(n log n),同时保持其他良好的性能特征

查看wiki page on sorting algorithms了解更多详情。

【讨论】:

在实践中,快速排序是最有效的。 @LuchianGrigore:对于实际上太常见的情况,快速排序具有可怕的最坏情况。通常最好使用组合,例如 introsort。 实际上,快速排序不再被认为是普通案例排序之王,尽管那是我上大学的时候。现在,Python 和 Java 都切换到了 timsort,这是一个经过很好修改的合并排序,因此合并步骤已经到位。

以上是关于如何降低排序的时间复杂度?的主要内容,如果未能解决你的问题,请参考以下文章

程序优化--降低复杂度

如何降低 C++ 中算法的时间复杂度?

如何降低这个问题的时间复杂度

如何降低以下代码块的时间复杂度?

如何降低装桶程序的时间复杂度?

基础排序算法详解与优化