算是老调重弹了,
昨天突然被女朋友一句话问傻了,说既然合并排序的时间复杂度是nlgn,而快排的时间复杂度最坏是n^2,那为什么要用快排呢?<--我的确在日常工作中用快排多,但这应该不代表快排就一定好(假设随机快排)
仔细想了想,
应该他们俩有各自的优势,甚至可以做个测试
--------to be continued 最近实在太忙!----------
--------update 11.19----------------------------------
今天又喝了杯咖啡!
为了可持续发展, 我决定,从明天起不喝低端的咖啡了,在买到好咖啡以前,绝不再喝。
--------------分割线-------------------------------------
-------------update 11.20:先说说快排那些事,我要深入一点地分析!----------------------------------
好,言归正传,先分析一下快排。
主要思想,我们知道了:(在重复一下)
一个“分治”的思想,函数QSort( A, S, E),接收3个参数,A为待排序数组,S为起始下标,E为终止下标
QSort的操作结果是, 将A[S...E]排序好(修改了原始数组),现在先默认为升序。
QSort的每次操作是,
a. 选一个支点A[k],把A[S...E]中比A[k]大的数移到A[k]后面(若为降序,则为前面),把比A[k]小的数移到A[k]前面(若为降序,则为后面),并记下这样操作后的A[k]被放到了数组的哪里(假设被放到了A[q]的位置上)。
b. QSort(A, S, q-1)
c. QSort(A, q+1, E)
该算法的正确性无需说明了。
-----------算法时间复杂度分析-------------
T(n) = O(n) + T(A) + T(n - A)
这样就可以看出该算法时间复杂度与它分的两块区域的规模有很大关系。
若每次都对半分,上面的公式可以变为
T(n) = O(n) + 2T(n/2)
解这个递归方程。
T(n) = O(nlgn),为排序的最优算法。
若每次都分成0个和n-1个,上面公式变为
T(n) = O(n) + T(n-1)
= O(n) + O(n-1) + ... +O(1)
= O(n^2)
退化为最差算法。
-------------算法细节分析-----------------------------------------
a.操作的过程称为patition,为这个算法比较重要的点。
如何实现呢?
下面是自己的想法(看了书之后忘了,还是受到原有算法的束缚)。
partition(A, S, E)
选支点A[k],令x = A[k]
(
回想一下要做的是什么,是把比支点大和比支点小的数“分割”开,最后达到的状态时什么样的呢?什么样的数字需要被移动呢?
最后的稳定状态:
一般情况下(先不考虑其他情况如分割成一边0个一边n-1个数), 前面一堆比A[k]小的数 - A[k] - 一堆比A[k]大的数,
是不是只要把在后面一堆中的较小数提到前面这个堆中?是的
[当然也可以把出现在前面的大数移动到后面]
围绕着上面的想法,就有了下面的过程。
)
用一个变量i 指示当前比支点小的最后一个数下标,并且它的下一个数是第一个比支点大的数(一般情况,还有其他特殊的)。
遍历A[S...E] : j = S...E,并用一个mark指示遍历过程是否出现了大数
i的初值 = S - 1;x = 支点的值; mark = true;
for j = S...E
do
{
if A[j] < x
if mark == true
i++
else
{ swap(A[i+1], A[j]) ; i++ ; }
else
mark = false;
}
return i+1
到这里似乎就可以达到我们的需求了,但是,我们漏了一点——支点混杂在整个需要调换的数组内,假如不采用一些手段,即所有操作都跳过支点,将需要一些很复杂的情形分析(我试图尝试,发现实在很累);
有一个很简单的方法,将支点与最后一个元素调换,这样所有调换操作都避开了支点,在所有操作结束后,把支点与A[i+1]交换即可。
事实上它的算法如何操作的呢?
(算法导论)
写的十分简单,根本不需要考虑mark
遍历A[S...E] : j = S...E,
i的初值 = S - 1;x = 支点的值;
for j = S...E
do
{
if A[j] < x
{ i++;
swap(A[i], A[j]) ;}//昨天写的匆忙,这里的i写成了i+1
}
swap(A[i+1],A[E])return i+1
看看sort()的源码如下:
--------to be continued 上面写的比较快,明天再做一定校对和修改。
转载请注明出处。
如果有任何问题,可以邮件联系本人.
weijyang@Foxmail.com