几篇排位很高的和原地归并算法的博客比如:
https://blog.csdn.net/acdreamers/article/details/24244643
都将原地归并算法的复杂度归为
O
(
n
log
n
)
O(n\log n)
O(nlogn)的。
但实际上经过一番计算发现,利用线性数组+手摇算法实现的原地归并,算法复杂度在
O
(
n
2
)
O(n^2)
O(n2)。
通过链表实现才是
O
(
n
log
n
)
O(n\log n)
O(nlogn)的。
链表实现nlogn
借用原文章中利用线性数组实现的图,简单说明这一点。
假设利用单向链表进行实现,我们将图中i
,j
,index
之前的元素用三个指针p1,p2,p3
指向。利用如下过程实现常数时间的手摇。
tmp = p1->next;
p1->next = p2->next;
p2->next = p3->next;
p3->next = tmp;
delete tmp;
那么即便最坏的情况也只是进行n/2次链表手摇。
T
(
n
)
=
c
⋅
n
2
+
2
T
(
n
2
)
T(n)=c\cdot\frac{n}{2}+2T(\frac{n}{2})
T(n)=c⋅2n+2T(2n)
复杂度为
O
(
n
log
n
)
O(n\log n)
O(nlogn)
手摇数组实现n方
相比之前提到的利用线性数组+手摇实现的,我们可以构造这样一个序列:
1,3,5,7, 2,4,6,8
这样每推进一位就需要进行一次手摇。而每次手摇算法的开销为
n
2
⋅
1
2
\displaystyle\frac{n}{2}\cdot\frac{1}{2}
2n⋅21,随序列剪短,需要进行手摇的序列长度从
n
2
\frac{n}{2}
2n逐一缩短为1。等差求和为
c
n
2
cn^2
cn2
但注意,这个算法复杂度并非
n
2
log
n
n^2\log n
n2logn 其实就算n方也本来就不如用冒泡
T
(
n
)
=
c
n
2
+
2
T
(
n
2
)
T(n)=cn^2+2T(\frac{n}{2})
T(n)=cn2+2T(2n)
求和为
∑
k
=
0
∞
c
(
n
2
k
)
2
⋅
2
k
=
c
n
2
∑
k
=
0
∞
1
2
k
\sum\limits_{k=0}^\infty c\left(\frac{n}{2^k}\right)^2\cdot 2^{k}=cn^2\sum\limits_{k=0}^\infty \frac{1}{2^k}
k=0∑∞c(2kn)2⋅2k=cn2k=0∑∞2k1
等号右边级数显然收敛到一个常数,故为
O
(
n
2
)
O(n^2)
O(n2)。