快速排序
(一)概念及实现
思想:分治策略。
快速排序的原理:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比基准数据小,另外一部分的所有数据都要比基准数据大,然后再按此方法对这两部分数据分别进行快速排序。
"保证列表的前半部分都小于后半部分"就使得前半部分的任何一个数从此以后都不再跟后半部分的数进行比较了,大大减少了数字间的比较次数。
具体如下(实现为升序):
设数组为a[0…n]。
1. 数组中找一个元素做为基准(temp),通常选数组的第一个数。
2. 对数组进行分区操作。使基准元素左边的值都小于temp,基准元素右边的值都大于等于temp。
3. 将temp值调整到分区后的正确位置。
4. 将基准两边的分区序列,分别进行步骤1~3。(递归)
5. 重复步骤1~4,直到排序完成。
以下是代码的算法思路: p代表传入数组的第一个元素的下标,r代表数组最后一个元素的下标
排序子数组 a[ p : r ],步骤如下:
(1)分解:以 a[ p ] 为基准元素将 a[ p : r ] 分成 3 段: a[ p : q - 1 ]、 a[ q ]、 a[ q + 1 : r ]。满足条件: a[ p : q - 1 ] 中任何一个元素 <= a[ q ]; a[ q + 1 : r ] 中任何一个元素 >= a[ q ]。下标 q 在划分过程中确定。
( 2)递归求解:通过递归调用快速排序算法分别对 a[ p : q - 1 ] 和 a[ q + 1 : r ] 进行排序。
(3)合并:对 a[ p : q - 1 ] 和 a[ q + 1 : r ] 的排序在各自的范围内进行,因此排好序后不需任何运算整个数组 a[ p : r ] 即完成排序。
上述算法的关键是函数 Partition ,其功能是以一个确定的基准元素 a[ p ] 对子数组 a[ p : r ] 进行划分,它是整个排序算法的关键。(这个算法思想可以用在很多算法思想上)
Partition例图:
代码如下:
<span style="font-size:18px;color:#333333;">#include<stdio.h>
#include<stdlib.h>
void swap(int *x,int *y) //交换函数
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}
int Partition(int a[],int low,int high)
{
int temp=a[low];
int i=low;
int j=high;
while(i<j)
{
while(a[j]>temp&&i<j)
j--;
if(i<j)
{
swap(&a[i],&a[j]);
i++;
}
while(a[i]<temp&&i<j)
i++;
if(i<j)
{
swap(&a[i],&a[j]);
j--;
}
}
return i;
}
void QuickSort(int a[],int p,int r)
{
if(p<r)
{
int q=Partition(a,p,r);
QuickSort(a,p,q-1); //左半边排序
QuickSort(a,q+1,r); //右半边排序
}
}
int main()
{
int i;
int a[10]={45,32,67,54,34,32,21,25,67,98};
QuickSort(a,0,9);
for(i=0;i<=9;i++)
printf("%d\n",a[i]);
return 0;
}</span>
不知道为什么编译时间好长。待我再研究下
(二)算法复杂度
1. 时间复杂度:O(nlog2n)
快速排序耗时的操作有:比较 + 交换(每次交换两次赋值)。时间复杂度如下:
1) 最好情况:选择的基准值刚好是中间值,分区后两分区包含元素个数接近相等。因为,总共经过x次分区,根据2^x<=n得出x=log2n,每次分区需用n-1个元素与基准比较。所以O(nlog2n)
2) 最坏情况:
最坏情况是枢纽元为最大或者最小数字,那么所有数都划分到一个序列去了 时间复杂度为O(n^2)
3) 渐进时间复杂度(平均时间复杂度):O(nlog2n)
2. 空间复杂度:O(1)
从实现原理可知,快速排序是在原输入数组上进行比较分区的(称“就地排序”),所需开辟的辅助空间跟输入数组规模无关,所以空间复杂度为:O(1)
(三)稳定性
快速是不稳定的,会改变相同元素的相对顺序。
(四)优化改进
当每次分区后,两个分区的元素个数相近时,效率最高。所以找一个比较有代表性的基准值就是关键。通常会采取如下方式:
1. 选取分区的第一个元素做为基准值。这种方式在分区基本有序情况下会分区不均。
2. 随机快排:每次分区的基准值是该分区的随机元素,这样就避免了有序导致的分布不均的问题
3. 平衡快排:取开头、结尾、中间3个数据,通过比较选出其中的中值。