排序算法5---快速排序
Posted 干货频道
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了排序算法5---快速排序相关的知识,希望对你有一定的参考价值。
快速排序是一种比较排序,它采用了一种分治的策略,分治法的思想就是,将一个问题分解为规模更小但结构与原问题一样的子问题,解决每个子问题又和解决原问题一样,继续分解,这种问题一般用递归解决。
快速排序的基本思想就是:首先通过一种方式将一个序列分为两部分,其中一部分的所有元素都比另一部分的小,然后再分别对这两部分按照以上方法继续排序,直到所有数据有序。
那么以何种方法将一个序列分为两部分,其中一部分的所有元素都比另一部分的小呢?我们可以先从序列中选出一个基准数(选基准数的方法很多,可以是随机数、可以是中间元素、可以是第一个元素,本文以序列第一个元素为基准数),然后通过比较,将所有比基准数小的元素放到基准数左边,将所有比基准数大的元素放到基准数右边,这样就实现了上面的分解。
算法原理
从序列(数组)中取出第一个元素作为基准数;
从序列后面向前面搜索,找到第一个小于基准数的元素,从序列前面向后面搜索,找到第一个大于等于基准数的元素,交换这两个元素位置;
重复第二步继续搜索,直到从后向前和从前向后碰到一起,将基准数放到这里,结束循环;
重复前三步,直到所有元素排好序。
算法分析
下面以数列 a[] = {6,2,3,8,1,5,9,4,7} 为例,用直观的图像来演示快速排序过程。
说明:上面是以序列第一个元素为基准数,当然也可以选其他元素为基准数。另一方面,这里是先从右向左找小于基准数的元素,再从左向右找大于基准数的元素(注意先后顺序:先从右向左,再从左向右),然后交换两个元素。其实我们也可以每次找到相应元素后,就和基准数交换;或者使用所谓的“挖坑法”,请自行搜索了解。
算法实现
这里用递归实现快速排序,递归函数的编写一定要注意退出循环的条件,稍有不慎就会成为死循环。下面的快速排序函数参数与前面的排序算法有些不同,这里有3个参数: arr 是要排序的数组指针;left 是数组左边界,一般是数组下标 0; right 是数组右边界,一般是数组下标 n-1。例如:数组 a[N],进行快速排序 quick_sort(a, 0, N-1);
static void swap(int *a, int *b)
{
int val = 0;
val = *a;
*a = *b;
*b = val;
}
// 快速排序
void quick_sort(int *arr, int left, int right)
{
int i = 0, j = 0;
int key = 0;
if(left > right)
return;
key = arr[left];
i = left;
j = right;
while(i < j)
{
while(i < j && arr[j] >= key) // 先从右向左
j--;
while(i < j && arr[i] <= key) // 再从左向右
i++;
swap(&arr[i], &arr[j]);
}
swap(&arr[left], &arr[i]);
quick_sort(arr, left, i - 1); // 递归,左边
quick_sort(arr, i + 1, right); // 递归,右边
}
算法改进
上述快速排序中使用了递归,也就涉及多次的函数调用,我们知道函数调用的开销也是很大的,以此为切入点,提出优化方式。先进行快速排序,当分解的序列个数比较少时,采用其他排序算法(比如插入排序),这样就减少了大量的函数调用过程,效率也会提升一些。
算法性能
时间复杂度
快速排序的平均时间复杂度为o(n㏒n)。
空间复杂度
快速排序的空间复杂度为 o(1)。因为只需要为两个元素交换位置时开辟一个空间,因此空间复杂度为o(1)。
稳定性
快速排序是一种不稳定的排序算法。
注意:上面的实现是不稳定的,但是快速排序的实现方法有多种,你也可以实现一个稳定的快速排序算法,因此分析一个排序算法的稳定性时,我们要看它的具体实现方法,切不能一概而论。
github源码连接:https://github.com/yqwung/sort
以上是关于排序算法5---快速排序的主要内容,如果未能解决你的问题,请参考以下文章