【问题标题】:Time complexity for Shell sort?Shell排序的时间复杂度?
【发布时间】:2012-10-07 09:23:46
【问题描述】:

首先,这是我的 Shell 排序代码(使用 Java):

public char[] shellSort(char[] chars) {
    int n = chars.length;
    int increment = n / 2;
    while(increment > 0) {
        int last = increment;
        while(last < n) {
            int current = last - increment;
            while(current >= 0) {
                if(chars[current] > chars[current + increment]) {
                    //swap
                    char tmp = chars[current];
                    chars[current] = chars[current + increment];
                    chars[current + increment] = tmp;
                    current -= increment;
                }
                else { break; }
            }
            last++;
        }
        increment /= 2;
    }
    return chars;
}

这是否是 Shell 排序的正确实现(暂时忘记最有效的间隙序列 - 例如 1、3、7、21...)?我问是因为我听说 Shell 排序的最佳情况时间复杂度是 O(n)。 (见http://en.wikipedia.org/wiki/Sorting_algorithm)。我看不到我的代码实现了这种效率水平。如果我向其中添加启发式方法,那么是的,但就目前而言,没有。

话虽如此,我现在的主要问题是 - 我很难为我的 Shell 排序实现计算 Big O 时间复杂度。我确定最外层循环为 O(log n),中间循环为 O(n),最内层循环也为 O(n),但我意识到内部两个循环实际上不是 O( n) - 他们会比这少得多 - 他们应该是什么?因为显然这个算法比 O((log n) n^2) 运行效率更高。

非常感谢任何指导,因为我非常迷茫! :P

【问题讨论】:

标签: algorithm big-o time-complexity shellsort


【解决方案1】:

实现的最坏情况是 Θ(n^2),最好情况是 O(nlogn),这对于 shell-sort 来说是合理的。

最佳情况∊ O(nlogn):

最好的情况是数组已经排序。这意味着内部 if 语句永远不会为真,从而使内部 while 循环成为恒定时间操作。使用您用于其他循环的边界给出 O(nlogn)。通过使用恒定数量的增量可以达到 O(n) 的最佳情况。

最坏情况∊ O(n^2):

给定每个循环的上限,在最坏的情况下,您会得到 O((log n)n^2)。但是为间隙大小 g 添加另一个变量。内部 while 所需的比较/交换次数现在

最坏情况∊Ω(n^2):

考虑所有偶数定位元素都大于中位数的数组。奇数和偶数元素在我们达到最后一个增量 1 之前不会进行比较。最后一次迭代所需的比较/交换次数是 Ω(n^2)。

【讨论】:

  • shellsort 使用的最坏情况比较次数并不总是 n 的二次方。对于 3x+1 增量,它是 O(N^3/2),对于 sedgewick 的序列,它是 O(N^4/3)。但是对于上面代码中使用的序列,它绝对是二次的。见en.wikipedia.org/wiki/Shellsort#Gap_sequences
  • 我的讲座材料指出,最知名的运行时间是 O(n^1.5)。 “已知”,因为分析至今仍未完成。
【解决方案2】:

插入排序

如果我们分析

static void sort(int[] ary) {
    int i, j, insertVal;
    int aryLen = ary.length;
    for (i = 1; i < aryLen; i++) {
        insertVal = ary[i];
        j = i;
        /*
         * while loop exits as soon as it finds left hand side element less than insertVal
         */
        while (j >= 1 && ary[j - 1] > insertVal) { 
            ary[j] = ary[j - 1];
            j--;
        }
        ary[j] = insertVal;
    }
}

因此在一般情况下,while循环将在中间退出

即 1/2 + 2/2 + 3/2 + 4/2 + .... + (n-1)/2 = Theta((n^2)/2) = Theta(n^2)

您在此处看到我们实现了 (n^2)/2,即使除以 2 并没有更多区别。

Shell Sort 只不过是使用 gap 的插入排序,例如 n/2, n/4, n/8, ...., 2, 1 意味着它利用了插入排序的最佳情况复杂性(即 while 循环退出),一旦我们在插入元素左侧找到小元素,它就会很快发生,因此它加起来就是总执行时间。

n/2 + n/4 + n/8 + n/16 + .... + n/n = n(1/2 + 1/4 + 1/8 + 1/16 + ... + 1/n) = nlogn(谐波级数)

因此它的时间复杂度接近于 n(logn)^2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-30
    • 1970-01-01
    • 2013-11-18
    • 2015-01-05
    • 2013-03-14
    相关资源
    最近更新 更多