快速排序(QuickSort)是对冒泡排序的一种改进,故在介绍快速排序之前,我们先介绍冒泡排序。
1、冒泡排序
原理:将第一个记录的关键字和第二个记录的关键字进行比较,若为逆序,则交换(假设正序输出),然后比较第二个记录和第三个记录的关键字。以此类推,直至第n-1个记录和第n个记录的关键字进行比较,这是第一趟。然后第二趟,第三趟……
过程演示:
算法代码:(算法很简单,双重循环)
#include <stdio.h>
#include <stdlib.h>
void main(){
int array[5] = { 5, 3, 1, 2, 8 };
int temp=array[0];//临时变量
int length=5;
for (int i = 0; i < length-1; i++){//外循环控制趟数
for (int j = 0; j < length-1-i; j++){//内循环控制比较
if (array[j]>array[j+1]){
temp = array[j];
array[j] = array[j+1];
array[j + 1] = temp;
}
}
}
for (int k = 0; k < length; k++){
printf("%d", array[k]);
}
system("pause");
}
2、快速排序
原理:快排是对冒泡排序的一种改进。基本思想是通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录继续进行排序,已达到整个序列有序。
算法叙述:一趟排序的具体做法是:附设两个指针low和high,它们的初值分别是low和high,设枢轴记录的关键字为pivotkey,则首先从high所指位置向前搜索找到第一个关键字小于pivotkey的记录,和枢轴记录交换之(即逆序交换,假设我们要从小到大输出),然后从low所指位置起向后搜索,找到第一个关键字大于pivotkey的记录,和枢轴相互交换(逆序交换)重复这两部,直至low=high为止。
此时记录被枢轴分成两部分,左边的都比枢轴小,右边的都比枢轴大。
然后进行第二趟,将枢轴左边的全部记录再当成一个记录序列,再次使用刚刚的方法。
算法演示:
(i就是low,j就是high)
算法代码:
#define MAXSIZE 20
typedef int KeyType;//定义关键字类型为int
typedef char InfoType;//定义其他信息类型为char
typedef struct{//定义记录类型
KeyType key;
InfoType otherinfo;
}RedType;
typedef struct{//定义顺序表类型
RedType r[MAXSIZE + 1];//r[0]闲置或作为哨兵
int length;//顺序表的长度
}SqList;
//在实现我们刚刚的算法时,每交换一次,需进行三次移动。
//但实际上对枢轴记录的移动是多余的,
//因为只有在一趟排序结束时,即low=high的位置才是枢轴记录的最后位置。
//故我们将枢轴暂存到r[0],一趟结束后再移到正确位置。
//此函数进行一趟排序。返回枢轴的位置。(此过程的演示只需把上图每一次交换的枢轴量用空白代替就行)
int partition(SqList *L, int low, int high){
int pivotkey;
L->r[0] = L->r[low];//用子表的第一个记录作为枢轴记录。
pivotkey = L->r[low].key;//用pivotpoint标识
while (low < high){
while (low<high&&L->r[high].key>=pivotkey){//从后向前找到要(向前)移动的关键字的下标
high--;
}
L->r[low] = L->r[high];//把找的的点(向前)移动
while (low < high&&L->r[low].key <= pivotkey){//从前往后找到要(向后)移动的关键字的下标
low++;
}
L->r[high] = L->r[low];//把找到的点(向后)移动
}
L->r[low] = L->r[0];//枢轴量放到该放置的位置
return low;//返回枢轴量的下标
}
void QSort(SqList *L, int low, int high){
//对顺序表中子序列L->r[low...high]作快速排序
int pivotloc;
if (low<high){//如果长度大于1
pivotloc = partition(L, low, high);//进行一趟排序,将L->r[low...high]分为两个子序列,本趟枢轴下标赋给pivotloc
QSort(L, low, pivotloc - 1);//对低子表进行递归排序
QSort(L, pivotloc + 1, high);//对高子表进行递归排序
}
}
void QuickSort(SqList *L){
QSort(L,1,L.length);
}
评价:
优点:快速排序的平均时间为T(n)=knInn,其中n为待排序列中记录的个数,k为某个时间常数,经验证明,在所有同数量级的此类排序方法中,快速排序的常数因子k最小。因此,就平均时间而言,快速排序是目前被认为最好的一种内部排序方法。
缺点:若初始记录序列按关键字有序或基本有序时,快速排序将退化为冒泡排序,时间复杂度为O(n^2).改进的方法是依“三者取中”的法则来选枢轴记录。(此处不详细介绍)