快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。该方法的基本思想是:
1.先从数列中取出一个数作为基准数。
2.分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
3.再对左右区间重复第二步,直到各区间只有一个数。
虽然快速排序称为分治法,但分治法这三个字显然无法很好的概括快速排序的全部步骤。
因此我的对快速排序作了进一步的说明:挖坑填数+分治法:
先来看实例吧,定义下面再给出(最好能用自己的话来总结定义,这样对实现代码会有帮助)。
以一个数组作为示例,取区间第一个数为基准数。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
72 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 48 | 85 |
初始时,i = 0; j = 9; X = a[i] = 72
由于已经将a[0]中的数保存到X中,可以理解成在数组a[0]上挖了个坑,可以将其它数据填充到这来。
从j开始向前找一个比X小或等于X的数。当j=8,符合条件,将a[8]挖出再填到上一个坑a[0]中:a[0]=a[8]; i++; 这样一个坑a[0]就被搞定了。
但又形成了一个新坑a[8],这怎么办了?简单,再找数字来填a[8]这个坑。这次从i开始向后找一个大于X的数,当i=3,符合条件,将a[3]挖出再填到上一个坑中:a[8]=a[3]; j--;
数组变为:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
48 | 6 | 57 | 88 | 60 | 42 | 83 | 73 | 88 | 85 |
i = 3; j = 7; X=72
再重复上面的步骤,先从后向前找,再从前向后找。
从j开始向前找,当j=5,符合条件,将a[5]挖出填到上一个坑中,a[3] = a[5]; i++;
从i开始向后找,当i=5时,由于i==j退出。
此时,i = j = 5,而a[5]刚好又是上次挖的坑,因此将X填入a[5]。
数组变为:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
48 | 6 | 57 | 42 | 60 | 72 | 83 | 73 | 88 | 85 |
可以看出a[5]前面的数字都小于它,a[5]后面的数字都大于它。因此再对a[0…4]和a[6…9]这二个子区间重复上述步骤就可以了。
对挖坑填数进行总结
1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。
2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。
照着这个总结很容易实现挖坑填数的代码:
1 package Sorting; 2 3 public class QuickSorting { 4 5 public static void main(String[] args) { 6 // TODO Auto-generated method stub 7 int arr[]={1,5,6,84,15,26,355,26,35,36,45,-5,36,45,18,4,44,58}; 8 int brr[]={1,5,6,84,15,26,35,36,45,18,4,44,58,555,63,78,98,15,0,-5,-8}; 9 QuickSort qs=new QuickSort(); 10 qs.sort1(0, arr.length-1,arr); 11 12 qs.sort2(0, brr.length-1,brr); 13 14 for(int e:arr){ 15 System.out.print(e+" "); 16 } 17 System.out.println(); 18 System.out.println("**********************************"); 19 for(int e:brr){ 20 System.out.print(e+" "); 21 } 22 } 23 } 24 25 class QuickSort { 26 27 // 1.挖坑填数+分治法 ****************** 28 29 public void sort1(int L,int R,int s[]){ 30 if(L<R){ 31 int i=L,j=R,x=s[L]; 32 while(i<j){ 33 //从右到左找第一个比x小的数 填坑 34 while(i<j && s[j]>=x){ 35 j--; } 36 37 if(i<j){ 38 s[i]=s[j]; //将s[j]填到s[i]中,s[j]就形成了一个新的坑 39 i++; 40 } 41 42 43 //从左到右找到第一个数比x大的数填最近出现的坑 44 while(i<j && s[i]<x){ 45 i++; } 46 47 if(i<j){ 48 s[j]=s[i]; //将s[i]填到s[j]中,s[i]就形成了一个新的坑 49 j--; 50 } 51 } 52 s[i]=x; 53 sort1(L,i-1,s); //递归调用 54 sort1(i+1,R,s); 55 } 56 } 57 58 59 // 2.二分法快速排序 60 public void sort2(int left,int right,int arr[] ){ 61 int l=left,r=right; 62 int pivot=arr[(left+right)/2]; //找中间值 63 int temp=0; 64 while(l<r){ 65 while(arr[l]<pivot) l++; 66 while(arr[r]>pivot) r--; 67 if(l>=r) break; 68 temp=arr[l]; 69 arr[l]=arr[r]; 70 arr[r]=temp; 71 if(arr[l]==pivot) --r; 72 if(arr[r]==pivot) ++l; 73 } 74 if(l==r){ 75 l++; 76 r--; 77 } 78 79 if(left<r) sort2(left,r,arr); 80 if(right>l) sort2(l,right,arr); 81 } 82 83 84 } 85