快速排序(quicksort)
快速排序算法(quicksort)
递归经常作为【分治法(divide-and-conquer)】技术的结果自然地出现。这种称为分治法的算法设计技术把一个大问题划分成多个较小的问题,然后采用相同的算法分别解决这些小问题。分治法的经典示例就是流行的排序算法----快速排序(quicksort)。快速排序算法的操作如下(为了简化,假设要排序的数组的下标从1到n)
1.选择数组元素e(作为“分割元素”),然后重新排列数组使得元素从1一直到i-1都是小于或等于元素e的,元素i包含e,而元素从i+1一直到n都是大于或等于e的。
2.通过递归地采用快速排序方法,对从1到i-1的元素进行排序。
3.通过递归地采用快速排序方法,对从i+1到n的元素进行排序。
执行完第1步后,元素e处在正确的位置上。因为e左侧的元素全部都是小于或等于e的,所以,一旦第2步对这些元素进行排序,那么这些小于或等于e的元素也将会处在正确的位置上;类似的理由也可应用于e右侧的元素。
该算法依赖于两个名为 low 和 high 的标记,这两个标记用来跟踪数组内的位置。开始,low 指向数组中的第一个元素,而 high 指向末尾元素。首先把第一个元素(分割元素)复制给其他地方的一个临时存储单元,从而在数组中留出一个“空位”。接下来,从右向左移动 high ,直到 high 指向小于分割元素的数时停止。然后然后把这个数复制给 low 指向的空位,这将产生一个新的空位(high 指向的)。现在从左向右移动 low ,寻找大于分割元素的数。在找到时,把这个找到的数复制给 high 指向的空位。重复执行此过程,交替操作 low 和 high 直到两者在数组中间的某处相遇时停止。此时,两个标记都将指向空位;只要把分割元素复制给空位就够了。
下面的图演示了这个过程:
此时,我们已经实现了目标:分割元素左侧的所有元素都小于或等于12,而其右侧的所有元素都大于或等于12.既然已经分割了数组,那么可以使用快速排序算法对数组的前4个元素(10、3、6、7)和后2个元素(15、18)进行递归快速排序了。
完整代码:
1 // 源代码仅作为参考,网上有很多相关代码。主要是要理解quicksort。 2 #include <stdio.h> 3 #define N 10 4 5 void quicksort(int a[], int low, int high); 6 int split(int a[], int low, int high); 7 8 void main() 9 { 10 int a[N], i; 11 12 printf("Enter %d numbers to be sorted:", N); 13 for (i=0; i<N; i++) 14 scanf("%d", &a[i]); 15 16 quicksort(a, 0, N-1); 17 printf("In sorted order:"); 18 for (i=0; i<N; i++) 19 printf("%d ", a[i]); 20 printf("\n"); 21 22 } 23 24 25 void quicksort(int a[], int low, int high) 26 { 27 int middle; 28 29 if (low>=high) return ; 30 middle = split(a, low, high); 31 quicksort(a, low, middle-1); 32 quicksort(a, middle+1, high); 33 } 34 35 int split(int a[], int low, int high) 36 { 37 int part_element = a[low]; 38 39 for (;;) 40 { 41 while (low<high && part_element<=a[high]) 42 high--; 43 if (low>=high) break; 44 a[low++] = a[high]; 45 46 while (low<high && a[low]<=part_element) 47 low++; 48 if (low>=high) break; 49 a[high--] = a[low]; 50 } 51 52 a[high] = part_element; 53 return high; 54 }
看一个动态图片,此图来源于:http://zh.wikipedia.org/wiki/%E5%BF%AB%E9%80%9F%E6%8E%92%E5%BA%8F