快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要Ο(n log n)次比较。在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见。事实上,快速排序通常明显比其他Ο(n log n) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。
快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。
步骤为:
- 从数列中挑出一个元素,称为 "基准"(pivot),
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作。
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代(iteration)中,它至少会把一个元素摆到它最后的位置去。
C语言:
#include <stdio.h> int a[100] = { 1, 2, 8, 7, 9, 5, 6, 4, 3, 66, 77, 33, 22, 11 }; /* 输出数组前n各元素 */ void prt(int n) { int i; for (i = 0; i < n; i++) { printf("%d\t", a[i]); } printf("\n"); } /* 数据交换 */ void swap(int *a, int *b) { int tmp; tmp = *a; *a = *b; *b = tmp; } void quick_sort(int a[], int left, int right) { int i = left + 1, j = right; int key = a[left]; if (left >= right) return; /* 从i++和j--两个方向搜索不满足条件的值并交换 * * 条件为:i++方向小于key,j--方向大于key */ while (1) { while (a[j] > key) j--; while (a[i] < key&&i<j) i++; if(i >= j) break; swap(&a[i],&a[j]); if(a[i]==key)j--; else i++; } /* 关键数据放到‘中间’ */ swap(&a[left],&a[j]); if(left < i - 1) quick_sort(a, left, i - 1); if(j + 1 < right) quick_sort(a, j + 1 , right); } int main(void) { /* 排序与输出 */ quick_sort(a, 0, 13); prt(14); return 0; }
C#:
public static void Sort(int[] numbers) { Sort(numbers, 0, numbers.Length - 1); } private static void Sort(int[] numbers, int left, int right) { if (left < right) { int middle = numbers[(left + right) / 2]; int i = left - 1; int j = right + 1; while (true) { while (numbers[++i] < middle) ; while (numbers[--j] > middle) ; if (i >= j) break; Swap(numbers, i, j); } Sort(numbers, left, i - 1); Sort(numbers, j + 1, right); } } private static void Swap(int[] numbers, int i, int j) { int number = numbers[i]; numbers[i] = numbers[j]; numbers[j] = number; }
JAVA:
import java.util.Comparator; import java.util.Random; public class Quicksort { public static final Random RND = new Random(); private static void swap(Object[] array, int i, int j) { Object tmp = array[i]; array[i] = array[j]; array[j] = tmp; } private static <E> int partition(E[] array, int begin, int end, Comparator<? super E> cmp) { int index = begin + RND.nextInt(end - begin + 1); E pivot = array[index]; swap(array, index, end); for (int i = index = begin; i < end; ++ i) { if (cmp.compare(array[i], pivot) <= 0) { swap(array, index++, i); } } swap(array, index, end); return (index); } private static <E> void qsort(E[] array, int begin, int end, Comparator<? super E> cmp) { if (end > begin) { int index = partition(array, begin, end, cmp); qsort(array, begin, index - 1, cmp); qsort(array, index + 1, end, cmp); } } public static <E> void sort(E[] array, Comparator<? super E> cmp) { qsort(array, 0, array.length - 1, cmp); } } /* * more efficient implements for quicksort. <br /> * use left, center and right median value (@see #median()) for the pivot, and * the more efficient inner loop for the core of the algorithm. */ class Sort { public static final int CUTOFF = 11; /** * quick sort algorithm. <br /> * * @param arr an array of Comparable items. <br /> */ public static <T extends Comparable<? super T>> void quicksort( T[] arr ) { quickSort( arr, 0, arr.length - 1 ); } /** * get the median of the left, center and right. <br /> * order these and hide the pivot by put it the end of * of the array. <br /> * * @param arr an array of Comparable items. <br /> * @param left the most-left index of the subarray. <br /> * @param right the most-right index of the subarray.<br /> * @return T */ public static <T extends Comparable<? super T>> T median( T[] arr, int left, int right ) { int center = ( left + right ) / 2; if ( arr[left].compareTo( arr[center] ) > 0 ) swapRef( arr, left, center ); if ( arr[left].compareTo( arr[right] ) > 0 ) swapRef( arr, left, right ); if ( arr[center].compareTo( arr[right] ) > 0 ) swapRef( arr, center, right ); swapRef( arr, center, right - 1 ); return arr[ right - 1 ]; } /** * internal method to sort the array with quick sort algorithm. <br /> * * @param arr an array of Comparable Items. <br /> * @param left the left-most index of the subarray. <br /> * @param right the right-most index of the subarray. <br /> */ private static <T extends Comparable<? super T>> void quickSort( T[] arr, int left, int right ) { if ( left + CUTOFF <= right ) { //find the pivot T pivot = median( arr, left, right ); //start partitioning int i = left, j = right - 1; for ( ; ; ) { while ( arr[++i].compareTo( pivot ) < 0 ) ; while ( arr[--j].compareTo( pivot ) > 0 ) ; if ( i < j ) swapRef( arr, i, j ); else break; } //swap the pivot reference back to the small collection. swapRef( arr, i, right - 1 ); quickSort( arr, left, i - 1 ); //sort the small collection. quickSort( arr, i + 1, right ); //sort the large collection. } else { //if the total number is less than CUTOFF we use insertion sort instead (cause it much more efficient). insertionSort( arr, left, right ); } } /** * method to swap references in an array.<br /> * * @param arr an array of Objects. <br /> * @param idx1 the index of the first element. <br /> * @param idx2 the index of the second element. <br /> */ public static <T> void swapRef( T[] arr, int idx1, int idx2 ) { T tmp = arr[idx1]; arr[idx1] = arr[idx2]; arr[idx2] = tmp; } /** * method to sort an subarray from start to end * with insertion sort algorithm. <br /> * * @param arr an array of Comparable items. <br /> * @param start the begining position. <br /> * @param end the end position. <br /> */ public static <T extends Comparable<? super T>> void insertionSort( T[] arr, int start, int end ) { int i; for ( int j = start + 1; j <= end; j++ ) { T tmp = arr[j]; for ( i = j; i > start && tmp.compareTo( arr[i - 1] ) < 0; i-- ) { arr[ i ] = arr[ i - 1 ]; } arr[ i ] = tmp; } } }