我想通过此代码了解shell排序的最坏情况分析。你能帮助我找出来吗? while
循环将执行 O(log n)
次,for
循环 O(n)
次;那么复杂性如何变成 O(n^2)
呢?一个完整的答案将不胜感激;我已经被困在这一天了。
int i, n = a.length, diff = n/2, interchange, temp;
while (diff > 0)
{
interchange=0;
for (i = 0; i < n - diff; i++)
{
if (a[i] > a[i + diff])
{
temp = a[i];
a[i] = a[i + diff];
a[i + diff] = temp;
interchange = 1;
}
}
if (interchange == 0)
{
diff = diff/2;
}
}
答案 0 :(得分:2)
您的算法不是shell排序。 Shell排序通过多次执行基本冒泡排序来工作。每次,您只考虑它们之间有k个元素间隙的元素。 k由以1结尾的递减序列给出。您的序列是n / 2,n / 4,n / 8,...,1,这很好。但是你没有为这个序列的每个成员执行冒泡排序;你只进行一次传球,这还不够。 O(n ^ 2)的最坏情况复杂性是由于冒泡排序。
请注意,在您的情况下,由于序列没有恒定长度,如果您修复算法,最坏情况下的复杂度将为O(n ^ 2 * logn)。
有关该算法的详细信息,wikipedia是您的朋友。
稍后编辑:
更正的代码是:
int i,n=a.length,diff=n/2,interchange,temp;
while(diff>0) {
interchange=0;
for(i=diff; i<n;i++) {
temp=a[i];
for (j = i; j >= gap && a[j-gap] > temp; j -= gap)
a[j] = a[j-gap];
a[j]=temp;
}
diff=diff/2;
}
请注意我没有检查,所以我可能错了。现在,你能看到嵌套的for循环使复杂性为O(n ^ 2)吗?
答案 1 :(得分:0)
您正在考虑的问题是您对平均情况和最坏情况感到困惑。在一般情况下,diff将定期更新并进行除法,从而导致while循环执行接近lgn次。但是,由于数据被交换,您有可能每个循环交换变为1。如果数据以最糟糕的方式排序,则每个循环都将移动数据。这将导致while循环执行n次而不是lgn。将while循环和for循环都放在o(n)处,你看o(n ^ 2)
考虑使用数字排序长度为4的数组:4,3,2,1。
第一个循环,你找到并切换4和2,以及3和1.这使你的循环:2,1,4,3。
下一个循环,没有任何反应,互换是0,所以它将你的差异减半。
第三循环,你找到并切换2和1,以及4和3:1,2,3,4
交换是1,差异仍然是1,所以你做另一个循环。没有任何事情发生,并且差异变为0.5退出你的循环。
在这种情况下,while循环执行n次,for循环执行n次。