快速排序算法可以说是最基本最常用的算法之一了,也是公认的最佳排序算法。虽然自己知道的基本原理是分治法,时间复杂度为O(N * logN),是非稳定排序。平时用也就是直接调用系统提供的库函数:C/C++ 中使用sort/qsort,Java中使用Arrays.sort。久而久之,快速排序的实现越来越模糊,以至于都快忘了实现算法中的递归关系。
正好在做一道题目时,又用到了快排,顺便再把快排捡起来。
【摘抄】
快速排序(QuickSort)
1、算法思想
快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。
(1) 分治法的基本思想
分治法的基本思想是:将原问题分解为若干个规模更小但结构与原问题相似的子问题。递归地解这些子问题,然后将这些子问题的解组合为原问题的解。
(2)快速排序的基本思想
设当前待排序的无序区为R[low..high],利用分治法可将快速排序的基本思想描述为:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
public void quick_sort(int[] a, int left, int right) { if(left < right){ int pivot = partition_swap(a,left,right); quick_sort(a,left,pivot-1); quick_sort(a,pivot+1,right); } }
调用时采用:quick_sort(array,0,array.length-1);
下面展开具体的分区过程:
有两种思路,一叫“挖坑填数”,另一个叫“交换法”
挖坑填数的思路是先把a[left]存起来作为基准值,left位置就作为第一个坑。然后,从右往左遍历当遇到比基准值小的情况,则把该值填到之前的坑里,当前位置变成新坑。从左往右遍历,当遇到比基准值大的情况,同样处理。直到最后左右汇合处的坑填上基准值。
private int partition(int[] a, int left, int right) { int i = left; int j = right; int pos = left; int tar = a[left]; while(i < j){ while(j>i){ if(a[j] > tar){ j--; }else{ a[pos] = a[j]; pos = j; i++; break; } } while(i<j){ if(a[i] < tar){ i++; }else{ a[pos] = a[i]; pos = i; j--; break; } } } a[pos] = tar; return pos; }
private int partition_swap(int[] a, int left, int right){ int pos = left; for(int i=left;i<right;i++){ if(a[i] < a[right]){ swap(a,pos,i); pos ++; } } swap(a,pos,right); return pos; } private void swap(int[] a, int x, int y) { int t = a[x]; a[x] = a[y]; a[y] = t; }