现在讨论一个借助“交换”实现排序的方法。主要有冒泡排序和快速排序(考虑从小到大的顺序)。
交换的意思是只在记录里面发生交换,而不借助其他的辅助空间进行存储以达到交换的目的。
一、冒泡排序
冒泡排序的过程都为大家所熟知,主要的思想是:
1)将第一个记录与第二个记录作比较,如果第一个记录的大小比第二个大,则将两个记录交换,然后比较第二个记录与第三个记录。直到第n-1个记录与第n个记录进行完比较为止,这样子记录中的最大值就“沉”到“水底”了,就成为这些记录的最后一项了;
2)重复第一步,但是此时的比较次数比第一次少一次,直到没有发生交换记录为止。
从冒泡的描述中可知,每趟排序都将记录中的最大值“下沉”,若为逆序的话,需要进行 n-1趟排序,且有n个记录,故冒泡排序的时间复杂度是O(n2)。
下面是冒泡排序的算法。
void BubleSort(SqList &L) {
i = 1;//从第一个开始比较
while(1) {
label = 0;//交换记录的标记,如果发生了交换就变为1,然后每次循环判断label是否为0,如果为0,则没有发生//交换,此时退出循环,冒泡排序结束
for(int j = 2;j < L.length;++i, ++j) {
if(L.[j] < L.[i]) {
L.[j]<->L.[r];//如果是逆序则记录发生交换
}
i = 1;//i重置为1,为下一趟排序做准备
if(label == 0) break;
}
}
二、快速排序
快速排序的发明者就是获得 1980年度图灵奖的英国牛津大学计算机科学家查尔斯.霍尔(Charles Antony Richard Hoare)。快速排序就是他在那个时候用原有的SHElLSORT(以算法的发明人D.L.Shell命令的通过调换并移动数据项实现排序的一种算法,发明于1959年)编程时分析了它的缺点而发明出来的。快速排序具有“快刀斩乱麻”的特点,能迅速地对乱序作大幅度调整,特别适合于因多次追加、删除而变得杂乱无章的数据集合。
在冒泡排序中,每趟排序都要进行n-i次比较,当遇到庞大的数据时,运行效率比较低。且在希尔排序中,每次都是缩小增量,在增量不同的情况下进行交换。快排的思想是:找到一个数,是这个数作为枢轴,使其满足位于其左边的数都比其小,位于其右边的数都比它大。这样,每趟排序就把枢轴(pivot)的位置定下来了,而且以后的每趟排序中,枢轴的位置都不会发生变化。通过一趟排序将待排记录分成独立的两部分,其中的一部分比另一部分的关键字都要小。然后分别对分割出来的几部分进行快速排序,直到整个序列有序为止。
下面是快速排序的算法实现:
void QuickSort(SqList &L) {
QSort(L, 1, L.length);
}
void QSort(SqList &L, int low, int high) {
if(low < high) {//low和high初始时分别指向表的头和尾
pivotlocation = Partion(L, low, high);//找到枢轴的位置
QSort(L, low, pivotlocation-1);//对枢轴的左边进行递归快排
QSort(L, pivotlocation+1, high);//对枢轴的右边进行递归快排
}
}
找到枢轴位置的算法实现:
int Partion(SqList L &L, int low, int high) {
L.r[0] = L.r[low];//保存枢轴的记录
pivotkey = L.r[low];//枢轴
while(low < high) {
while(low < high && L.r[high] >= pivotkey) --high;
L.r[low] = L.r[high];//比枢轴大的移到高端
while(low < high && L.r[low] <= pivotkey) --low;
L.r[high] = L.r[low];//比枢轴小的移到低端
}
L.r[low] = L.r[0];//枢轴记录到位
return low;
}