一、快速排序算法
快速排序实现基本思想是:通过一次排序将整个无序表分成相互独立的两部分,其中一部分中的数据都比另一部分中包含的数据的值小,然后继续沿用此方法分别对两部分进行同样的操作,直到每一个小部分不可再分,所得到的整个序列就成为了有序序列。
二、快速排序流程
(1) 从数列中挑出一个基准值。
(2) 将所有比基准值小的摆放在基准前面,所有比基准值大的摆在基准的后面(相同的数可以到任一边);在这个分区退出之后,该基准就处于数列的中间位置。
(3) 递归地把"基准值前面的子数列"和"基准值后面的子数列"进行排序。
例如,对无序表{49,38,65,97,76,13,27,49}进行快速排序,大致过程为:
- 首先从表中选取一个记录的关键字作为分割点(称为“枢轴”或者支点,一般选择第一个关键字),例如选取 49;
- 将表格中大于 49 个放置于 49 的右侧,小于 49 的放置于 49 的左侧,假设完成后的无序表为:{27,38,13,49,65,97,76,49};
- 以 49 为支点,将整个无序表分割成了两个部分,分别为{27,38,13}和{65,97,76,49},继续采用此种方法分别对两个子表进行排序;
- 前部分子表以 27 为支点,排序后的子表为{13,27,38},此部分已经有序;后部分子表以 65 为支点,排序后的子表为{49,65,97,76};
- 此时前半部分子表中的数据已完成排序;后部分子表继续以 65为支点,将其分割为{49}和{97,76},前者不需排序,后者排序后的结果为{76,97};
- 通过以上几步的排序,最后由子表{13,27,38}、{49}、{49}、{65}、{76,97}构成有序表:{13,27,38,49,49,65,76,97};
整个过程中最重要的是实现第 2 步的分割操作,具体实现过程为:
- 设置两个指针 low 和 high,分别指向无序表的表头和表尾,如下图所示:
- 先由 high 指针从右往左依次遍历,直到找到一个比 49 小的关键字,所以 high 指针走到 27 的地方停止。找到之后将该关键字同 low 指向的关键字进行互换:
- 然后指针 low 从左往右依次遍历,直到找到一个比 49 大的关键字为止,所以 low 指针走到 65 的地方停止。同样找到后同 high 指向的关键字进行互换:
- 指针 high 继续左移,到 13 所在的位置停止(13<49),然后同 low 指向的关键字进行互换:
- 指针 low 继续右移,到 97 所在的位置停止(97>49),然后同 high 指向的关键字互换位置:
- 指针 high 继续左移,此时两指针相遇,整个过程结束;
三、代码实现(python)
def quick_sort(num_list, first, last):
if first >= last:
return
p = first
q = last
while q > p:
if num_list[q] >= num_list[first]:
q -= 1
elif num_list[p] < num_list[first]:
p += 1
else:
num_list[p], num_list[q] = num_list[q], num_list[p]
num_list[p] = num_list[first]
quick_sort(num_list, first, q-1)
quick_sort(num_list, q+1, last)
if __name__ == '__main__':
num_list = [44, 23, 1, 14, 6, 9, 4, 5, 33]
length = len(num_list)
quick_sort(num_list, 0, length - 1)
print(num_list)
四、时间复杂度和空间复杂度
1、快速排序算法的性能
2、时间复杂度
当数据有序时,以第一个关键字为基准分为两个子序列,前一个子序列为空,此时执行效率最差。
而当数据随机分布时,以第一个关键字为基准分为两个子序列,两个子序列的元素个数接近相等,此时执行效率最好。
3、空间复杂度
快速排序在每次分割的过程中,需要 1 个空间存储基准值。而快速排序的大概需要 logN次的分割处理,所以占用空间也是 logN 个。
4、算法稳定性
在快速排序中,相等元素可能会因为分区而交换顺序,所以它是不稳定的算法。