快速算法的思路就是对数组分区排序
一般的先取第一个数作为基准数,然后将整个数列按大小分成两个区,大于基准数的在右边,小于的在左边。然后分别对分区按照上面的方法在进行分区排序,直到整个数组排序好。
下面以一个数组为例:
6,7,1,8,3,9,2,5,10
一般的以第一个数作为基准数,那么怎么才能将大于6的移到右边,小于6的移到左边呢?
假如用6从头到尾比的话,6比7小不动,6比1大换位,这样无法排序(冒泡排序是相邻的两个数比较换位)。
假如再创建一个一样大的空数组,将比6小的放在左边,大的放在右边,剩下的一个位子就是基准数,并记录下它的位子,这样也很麻烦,递归下去需要的中间数会越来越多,而且没有头和尾。另外创建这么多数组也很耗费内存,最好是能够在原来的数组上面进行修改。
既然要分区,肯定有个中间位置,假定中间的指针叫middle,显然这个Middle可以通过比较得出,那么必须要两个指针来表示这个区的位置,假定这个区的开始是left,结尾是right。要递归的分区下去,需要这样三个参数,int[] array, int left,int right 。那么递归什么时候结束呢?当不能再分区的时候就结束了,吗么什么时候不能再分区呢?left=right的时候。
这里最重要的就是一个求分区中间值的函数,我们假定为getMiddle(int array ,int left ,int right)
排序的函数 sort(int [] array,int left ,int right)
按照上面的思路那么这个sort函数的函数体如下
public void sort(int [] array ,int left ,int right) { if(left<right) { int middle=getMiddle(array,left,right); sort(array, left, middle-1);//对左边的进行分区
sort(array, middle+1, right);//对右边的进行分区
} }
现在要实现getMiddle函数,这个函数需要在分区中找到中间的位置,而且要在原数组上进行操作。
首先将该区的第一个即 left 和最后一个即right 进行比较
目的是在右边找到一个数比left指向的数小,并把它替换掉left指向的位置,那么这样替换下去会不会造成left指向的数消失呢?当然持续在右边找的话肯定会这样的,怎么样才能避免这样的问题?那就是右边找完了,替换掉left指向的那个数,即right指向的那个数现在有重复,现在left和right指向的那个数是一样的,就需要在right的左边找到一个数能够取代right的数,这样就从left开始比较,要找到一个比基准数大的去替换掉右边,只要left<right就不停止。当left和right相等的时候这个位置的左边都比基准数小,右边都比基准数大。这个位置就是Middle。
public int getMiddle(int[] list, int left, int right) { int pvoit=list[left]; while(left<right) { while(left<right && list[right]>pvoit) { right--; } list[left]=list[right]; while(left<right && list[left]<pvoit) { left++; } list[right]=list[left]; } list[left]=pvoit; return left; //返回中轴的位置 }
最后测试
public void quick(int[] str) { if (str.length > 0) { //查看数组是否为空 sort(str, 0, str.length - 1); } }