快速排序也是使用了分治思想的排序方法,但与归并排序不一样的是“分”的时候的依据。归并排序“分”的依据是对半分,不管大小,而快速排序则是选定数组中的一个值,以这个值为依据,将数组分为三个部分:小于这个值的部分,大于等于这个值的部分,这个值。这样就以选定的点将数组分为两部分(小于值的部分,大于等于值的部分),然后再通过迭代对这两个部分分别继续执行这样一个“分”的过程,直至最后只剩下1-2个元素,即无法再“分”时,此时数组也排序完成。
下面以图示的方法展示一下第一次“分”的过程。
首先给出要排序的数组
l
=
[
2
,
8
,
7
,
1
,
3
,
5
,
6
,
4
]
l=[2,8,7,1,3,5,6,4]
l=[2,8,7,1,3,5,6,4],
s
t
a
sta
sta和
e
n
d
end
end分别为数组的首尾下标。利用
i
i
i和
j
j
j这两个数进行迭代。令
i
=
s
t
a
−
1
,
j
=
s
t
a
i=sta-1,j=sta
i=sta−1,j=sta。
迭代过程中分成了这样几个部分:
i
i
i所在的位置是
<
e
n
d
<end
<end的最新的一个值,在“分”的最后,将返回
i
+
1
i+1
i+1,即用来比较的值的位置,以供下次迭代。
具体的python代码实现如下。
#将数组分为两部分
def partition(l0,sta,end):
i=sta-1
for j in range(sta,end):
if l0[j]<l0[end]:
i=i+1
#如果j所在的位置的值小于end,则i往前进一步,并与j的值交换,即将一个新的值加入到<end的区域
x=l0[i]
l0[i]=l0[j]
l0[j]=x
#一次“分”结束,将用于比较的值放在应该在的地方(两个区域的中间)
i=i+1
x=l0[i]
l0[i]=l0[end]
l0[end]=x
return i
def quicksort(l0,sta,end):
#当至少存在两个元素时,才进行接下来的分解
if sta<end:
mid=partition(l0,sta,end)
#分成的sta—mid-1,mid+1—end两个区域接着进行分解、迭代
quicksort(l0,sta,mid-1)
quicksort(l0,mid+1,end)
return l0
快速排序的最坏情况,即每次分解时都极其不平衡,分解为
n
−
1
n-1
n−1个元素和
0
0
0个元素,这样分解操作的时间复杂度为
Θ
(
n
)
Θ(n)
Θ(n),而对大小为
0
0
0的数组进行迭代会直接返回,时间复杂度可以忽略。这样算法运行时间的递归式为
T
(
n
)
=
T
(
n
−
1
)
+
Θ
(
n
)
T(n)=T(n-1)+Θ(n)
T(n)=T(n−1)+Θ(n)
解为
T
(
n
)
=
Θ
(
n
2
)
T(n)=Θ(n^2)
T(n)=Θ(n2)
而最好的情况则是每次都对半分,这样算出的时间复杂度为
Θ
(
n
l
g
n
)
Θ(nlgn)
Θ(nlgn)
而即使是每次的划分达到
9
:
1
9:1
9:1这样一个很不平衡的状态,最终算出的时间复杂度也是
Θ
(
n
l
g
n
)
Θ(nlgn)
Θ(nlgn),事实上,即使是
99
:
1
99:1
99:1也是这样的时间复杂度。(结论和推导均来自《算法导论》)
所以快速排序法的期望时间复杂度为
Θ
(
n
l
g
n
)
Θ(nlgn)
Θ(nlgn),是一个优秀的排序算法。