【问题标题】:Running Time For Insertion Sort插入排序的运行时间
【发布时间】:2013-01-24 04:29:17
【问题描述】:
for (int p=1; p < a.size(); p++) {
    int tmp = a[p];
    for(j=p; j>0 && tmp < a[j-1]; j--) {
        a[j] = a[j-1];
    }
    a[j] = tmp;
}

我无法确定插入排序的最坏情况。 所以,给定的数组是降序排列的,我们要按升序排列。

外循环遍历数组。因此,它运行(n 次)。在) int tmp=a[p] ---- 这个语句被执行了 n 次。在) 内部循环执行 (1+2+3+4+5+6+.... +n-1) 次。 O(n^2) a[j]= tmp-------- 该语句被执行 n 次。 O(n)

我不确定如何找到插入排序的运行时间? 如果可以,请纠正我的工作。 谢谢。

【问题讨论】:

  • 最坏情况的运行时间为 O(n^2)。但我不确定如何获得它。

标签: c++ sorting c++11 time-complexity insertion-sort


【解决方案1】:

这是插入排序的两行通用 C++11 实现

template< typename ForwardIterator, typename Compare = std::less<typename std::iterator_traits<ForwardIterator>::value_type> >
void insertion_sort(ForwardIterator first, ForwardIterator last, Compare cmp = Compare())
{
        for (auto it = first; it != last; ++it) {
                auto const insertion = std::upper_bound(first, it, *it, cmp);
                std::rotate(insertion, it, std::next(it));
        }
}

该算法采用一系列元素(由两个迭代器 firstlast 给出)和一个比较函数(对于指向的元素,默认为可能内置的 operator&lt;)。

主循环(元素数量呈线性关系)保持子区间[first, it) 排序,并反复搜索放置下一个元素的插入点。它相当于你的主循环。它使用binary search(对数复杂度)来实现。在您的代码中,您使用反向线性搜索(具有线性复杂性但可能有更好的缓存行为)。

找到插入点后,它只是rotates这两个范围[insertion, it)[it, it+1),意思是把当前元素交换到插入点。这种旋转与到目前为止已排序的元素数量呈线性关系。由于嵌套在主循环中,所以插入排序的整体复杂度是二次的,即O(N^2)。您的代码集成了插入点的交换和搜索,但这不会改变复杂性。

请注意,当输入范围已经排序时,插入点将始终等于it 指向的元素,这意味着std::rotate 根本不需要交换任何内容。足够智能和优化的编译器应该能够执行该优化。如果是这种情况,则对已排序范围的插入排序具有线性复杂度。

here 给出了类似的 2 行选择排序方法。

【讨论】:

    【解决方案2】:

    外循环执行n次。

    内部循环的每次运行都会执行 0 到 p-1 次,其中 p 从 0 到 n 变化。在最坏的情况下,它将执行 p-1 次。如果 p 从 0 变化到 n,则平均而言,p 为 n/2。因此,内循环的最坏情况复杂度是 O(p-1) = O(n/2-1) = O(n)。

    除了循环之外,代码都是 O(1)(最重要的是,内部循环内的代码是),所以只有循环才是重要的。

    O(n) * O(n) = O(n^2)。

    QED。

    这大概是你自己给出的分析。

    【讨论】:

      猜你喜欢
      • 2017-08-18
      • 1970-01-01
      • 1970-01-01
      • 2012-03-22
      • 2017-01-16
      • 1970-01-01
      • 2011-09-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多