如何证明以下算法具有 O(nlogn) 时间复杂度

Posted

技术标签:

【中文标题】如何证明以下算法具有 O(nlogn) 时间复杂度【英文标题】:How do I demonstrate the following algorithm has O(nlogn) time complexity 【发布时间】:2019-10-21 14:18:28 【问题描述】:

这是一种算法,它以 O(nlogn) 时间复杂度找到数组的最小降行数和行本身。练习的另一部分是使用这些降序行来实现耐心排序,它也必须是 O(nlogn)(即来自 c = 1 部分)。我不明白这两种情况下 logn 部分的来源。

#include <iostream>
#include <fstream>
#include <list>
using namespace std;

ifstream f("data.in");

int main()

    int n, v[100];
    f >> n;
    for (int i = 0; i < n; i++)
        f >> v[i];
    list<int> aux;
    aux.push_back(v[0]);
    list<list<int> > rows;
    rows.push_back(aux);
    for (int i = 1; i < n; i++)
    
        int selected = 0;
        for (list<list<int> >::iterator it = rows.begin(); it != rows.end(); it++)
        
            if (it->back() > v[i])
            
                it->push_back(v[i]);
                selected = 1;
                break;
            
        
        if (!selected)
        
            list<int> aux;
            aux.push_back(v[i]);
            rows.push_back(aux);
        

    
    for (list<list<int> >::iterator it = rows.begin(); it != rows.end(); it++)
    
        for (list<int>:: iterator it2 = it->begin(); it2 != it->end(); it2++)
            cout << *it2 << " ";
        cout << endl;
    

    int c = 1;
    if (c == 1)
    
        int s[100];
        for (int i = 0; i < n; i++)
        
            list<list<int> >::iterator it = rows.begin();
            int minim = it->back();
            it++;
            while (it != rows.end())
            
                if (!it->empty())
                    if (it->back() < minim)
                        minim = it->back();
                it++;
            
            it = rows.begin();
            while (it != rows.end())
            
                    if (it->back() == minim)
                    
                        it->pop_back();
                        if (it->empty())
                            rows.erase(it);
                        break;
                    
                it++;
            
            s[i] = minim;
        
        for (int i = 0; i < n; i++)
            cout << s[i] << " ";

    


【问题讨论】:

我想是O(n^2)?只考虑一个递增的输入序列。 添加到苹果苹果的评论中:您的代码的两个部分都可以改进为 O(n log n)。这可能就是您的导师所要求的。 【参考方案1】:

您的外部循环处理每条输入数据,因此增长是线性的,例如在)。您的内部循环仅处理完整输入数据的较小子集,并且增长是对数的,例如O(log n)。因此增长是线性的,例如O(nlogn)。如果内部循环处理每条输入数据,则增长将是二次的,例如O(n^2)

可以在这里找到一个很好的解释:

What does O(log n) mean exactly?

编辑:我的错误。我同意原帖下的 cmets 程序的增长似乎是 O(n^2)。我在转弯时有点快。快速浏览一下,最初在我看来,内循环执行了 log n 次。但看起来第二次 n 迭代中的内部循环并非如此。但是,据我了解,第一个内循环在我看来似乎被执行 log n 次(因此对行进行排序的增长顺序是 O(nlogn)),但也许我弄错了。

【讨论】:

以上是关于如何证明以下算法具有 O(nlogn) 时间复杂度的主要内容,如果未能解决你的问题,请参考以下文章

创建两个不均匀子问题的分治算法的时间复杂度。

O(nlogn) + O(n) 的时间复杂度是不是只是 O(nlogn)?

最长递增子序列 LIS 时间复杂度O(nlogn)的Java实现

九大排序算法时间复杂度空间复杂度稳定性

算法 -- o, o(n), o(logn), o(nlogn)

算法系列排序算法下篇--如何超越排序算法下界