交换类排序的基本思想是通过交换逆序元素而最终达到所有元素有序,这里的逆序是个广义概念,如果按照降序排序,那么前小后大的相邻元素就为逆序。常见的交换类排序方法有冒泡排序和快速排序。
1.冒泡排序
冒泡排序法的思想比较简单,依次扫描待排序的序列,并且从第一个元素开始比较相邻两个元素之间的大小,如果逆序则交换。假如有一个记录序列r[1,length],以升序为例,在第i趟排序过程中需要对前length-(i-1)个元素进行逆序交换,最终这些记录中的最大元素将被交换到序列中第length-(i-1)这个位置上。
void bubbleSort(int *r, int length) { int n, change; int i, j, k; n = length; change = 1; for ( i = 1; i <= n - 1 && change; i++) { change = 0; for ( j = 1; j <= n - i; j++) if (r[j] > r[j + 1]) { r[0] = r[j]; r[j] = r[j + 1]; r[j + 1] = r[0]; change = 1; } output(r, length); } }
对于n个元素的序列来说,整个冒泡排序最多进行n-1趟。这里还特别的增加了一个标志位change,只要做了逆序交换change就为真,如果某一趟中没有做任何交换,说明序列已经有序,则change为假,此时整个排序可以提前停止。
2.快速排序
冒泡算法中对相邻元素的交换一次只能消除一个逆序,如果通过交换两个不相邻的元素能一次消除多个逆序,则会增加整个排序的速度。快速排序就是基于这样的目的,在一次交换中可以消除多个逆序。
快速排序的基本思想是在待排序记录中选择一个记录作为标准,将大于该标准的所有元素移到该标准之后,将小于该标准的所有元素移到该标准之前。最终将待排序的记录分成两个子序列,而标准元素插入到两个子序列之间,上述过程为一趟快速排序过程。接下来再对两个子序列进行快速排序,不断的分割子表,直到子表长度不超过1为止,此时所有的记录都是有序的。
根据上述分析,可以通过递归来实现快速排序法。quickPass()用于一趟快速排序,并且返回标准元素的位置pos。
void quickSort(int *r, int low, int high, int length) { int pos; if (low < high) { pos = quickPass(r, low, high); quickSort(r, low, pos - 1, length); quickSort(r, pos + 1, high, length); output(r, length); } }
quickPass()用于实现一趟快速排序,一趟快速排序结束的条件是low不小于high。可以看到快速排序中是将low和high两个不相邻位置的元素进行交换。
int quickPass(int *r, int left, int right) { int low, high; low = left; high = right; r[0] = r[low]; while (low < high) { while (low < high && r[high] >= r[0]) high--; if (low < high) { r[low] = r[high]; low++; } while (low < high && r[low] <= r[0]) low++; if (low < high) { r[high] = r[low]; high--; } } r[low] = r[0]; return low; }
这里也用到了r[0],用它来存储标准元素,当一趟快速排序完成后,将标准元素插入low所指位置。