快速排序(Quick Sort)是通过分治的思想来进行排序。它的主要思想是:取数组中的一个数作为
基准值(往往取数组中的第一个数),把所有小于基准值的数都放在它的左侧,再把所有大于基准值的数都放在它的右侧。随后,对基准值左右两侧的数组分别进行快速排序。
快速排序的平均时间复杂度是O(),最好情况下的时间复杂度是O()。最坏情况下,快速排序的时间复杂度可能退化为O(),但这种情况很少见。快速排序是一个不稳定的算法,如果使用得当,快速排序的速度可以达到归并排序和堆排序的数倍,所以快速排序是一种极其常用的算法。
写了三种方法,思路都是一样的,具体细节不一样。
第一种方法比较简单,也好理解
nums = [5, 6, 4, 5, 3, 1, 8, 9, 7]
def QuickSort(num):
# 若列表长度为1,直接输出不用排序
if len(num) <= 1:
return num
# 取数组的第一个数作为基值
key = num[0]
# 定义空列表用来储存大于/小于/等于基准值的元素
llist, mlist, rlist = [], [], []
# 定义空列表用来储存大于/小于/等于基准值的元素
for i in range(0, len(num)): # 遍历列表,把元素归类到三个列表中
if num[i] < key:
llist.append(num[i])
elif num[i] > key:
rlist.append(num[i])
else:
mlist.append(num[i])
# 对左右两个列表进行快排,拼接三个列表并返回
return QuickSort(llist) + mlist + QuickSort(rlist)
print(QuickSort(nums))
以这种方法来实现快速排序需要额外的开辟空间给用于归类的列表。并且相似的思路用于其他的编程语言是效率低。
那么,我们就需要对这种方法来进行优化。此时,用一个变量来储存基准值,然后用两个指针,一个在最左边从左往右遍历,另一个在最右边从又往左遍历。开始遍历的时候可以把基准值在数组中的位置,也就是第一个元素,视作一个没有元素的空位。
第一步,先移动右指针,从右往左移动,直到指针指向的元素小于基准值为止。并把右指针指向的值赋给左指针指向的位置
第二部,移动左指针,从左往右移动,直到指针指向的元素大于等于基准值时停下。并把左指针指向的值赋给右指针指向的位置。
第三步,重复以上操作,不断交替移动左右指针并赋值。
第四步,当左右指针重合时,所有必要的移动都已经完成。左右指针共同指向的位置就是基准值在有序数组中的位置。它的值大于它左侧所有的元素并小于它右侧所有的元素。剩余操作为递归排序左右子数组,直到全部数组排序完成。
# QSort
nus = [4, 5, 1, 2, 3, 5, 4, 1]
# left,right分别为子数组中第一个元素和最后一个元素在原数组中的位置
def QSort(left, right):
# 边界条件
if left >= right:
return
# 初始化左右指针的初始值
l, r, key = left, right, nus[left]
# 调整元素的位置
while l < r:
while l < r and nus[r] >= key:
r -= 1
nus[l] = nus[r]
while l < r and nus[l] <= key:
l += 1
nus[r] = nus[l]
# 把基准值赋给左右指针共同指向的位置
nus[r] = key
# 对左侧数组排序
QSort(left, l-1)
# 对右侧数组排序
QSort(l+1, right)
QSort(0, len(nus) - 1)
print(nus)
相对于第一种方法,这种方法解决了需要开辟空间的问题,元素与元素之间在原来的数组内部进行位置的交换,。但是这中方法没有采用直接将数组传入函数的方法,而是把子数组第一个和最后一个元素的位置穿入函数中,就导致了在实际使用的时候并不方便,因为每次使用的时候就需要调整。
这就需要第三种方法,既包含了前两种方法的优点使用起来也非常方便,首先这种方法需要需要把数组传入函数当中,然后再运用指针交换的形式来进行快速排序。
def QSort(lst, left, right):
if left >= right:
return
l, r, key = left, right, lst[left]
while l < r:
while l < r and lst[r] >= key:
r -=1
lst[l] = lst[r]
while l < r and lst[l] < key:
l += 1
lst[r] = lst[l]
lst[l] = key
QSort(lst, left, l-1)
QSort(lst, l+1, right)
return lst
nus = [4, 5, 1, 2, 3, 5, 4, 1]
print(QSort(nus, 0, len(nus) - 1))