如果列表已预先排序(最好的情况),我对shell排序的运行时间感到困惑。是O(n)还是O(n log n)?
for(k=n/2; k>0; k/=2)
for(i=k; i<n; i++)
for(j=i;j>k; j-=k)
if(a[j-k]>a[j]) swap
else break;
Shell排序基于插入排序,插入排序有预先排序列表的O(n)运行时间,但是,通过引入空隙(最外层循环),我不知道它是否使shell的运行时间对预排序列表排序O(n log n)。
感谢您的帮助
答案 0 :(得分:2)
在数据已经订购的最佳情况下,最内层的循环永远不会交换。它将始终立即中断,因为已知左值小于正确的值:
for(k=n/2; k>0; k/=2)
for(i=k; i<n; i++)
for(j=i;j>k; j-=k)
if(false) swap
else break;
所以,算法崩溃了:
for(k=n/2; k>0; k/=2)
for(i=k; i<n; i++)
no_op()
最好的情况是:
O((n - n/2) + (n - n/4) + (n - n/8) + ... + (n - 1))
= O(nlog(n) - n)
= O(nlog(n))
那就是according to Wikipedia,Shell Sort的其他一些变种确实有O(N)最好的情况。
答案 1 :(得分:1)
我认为(至少正常实施)它大约为O(n log n),但具体数字取决于您使用的进展。
例如,在第一次迭代中,您调用插入排序,比方说,五次,每次排序每五个元素。由于每个元素在排序的元素数量上都是线性的,因此整体上会出现线性复杂度。
在下一次迭代中,您调用插入排序,例如两次,对每个其他元素进行排序。再次,线性整体。
在第三个中,你对每个元素进行插入排序,再次是线性的。
简而言之,你有一个线性算法调用(大致)对数次数,因此它应该大约为O(n log n)。这假设您使用的步长有某种几何级数,这很常见,但(可能)并非绝对必要。
答案 2 :(得分:0)
最好的情况是O(n)。这就是原因:
让我们从插入排序开始。已排序的n个条目列表将需要n-1个比较才能完成(无需交换)。
将插入排序放在具有单个增量的shellort的上下文中.1。已排序的n个条目列表将需要n减去间隙(1)。
假设您有两个间隙5后跟1且n大于5.已经排序的列表将需要n-5个比较来处理第一个间隙(无需交换)以及第二个或2n-的n-1个比较6(无需交换)。
如果使用n作为输入来产生间隙并不重要。最后,每个间隙都是一个常数值c(最终c为1)。
因此,最佳案例的算法是&#34; n *间隙数 - 所有间隙的总和&#34;。
我不知道&#34; n *间隙的数量 - ......&#34;可能是O(n)以外的任何东西。
我知道大多数讨论都把它作为别的东西,我得到的印象是没有人打扰坐下来做数学。如你所见,它不是火箭科学。