快速排序
快速排序
简介
快速排序是一种划分交换排序。它采用了一种分治的策略,通常称其为分治法。与冒泡排序同属于交换排序。
算法原理
从数组中取出一个数作为基准数,通常是第一个元素,将比这个数大的元素放在它的右边,比他小的元素放在它的左边,然后对左右区间进行以上操作。直到数组变为有序数组。
代码实现
代码实现有几种方式,第一种是找到一个符合条件的元素就交换,不容易理解(至少在我看来是这样)。
第二种是找到符合条件的元素进行赋值,通过一个临时变量和几次赋值操作完成元素的交换。与第一种相比容易理解一些。代码如下:
public static int[] quickSort(int a[], int startIndex, int endIndex)
{
if(startIndex <endIndex){//数组长度大于1时进行递归
int i=startIndex;
int j=endIndex;
int temp=a[i];//将a[i]这个元素挖空,等待其他数据填入,并将a[i]的值取出存入到临时变量中
while(i<j){ //控制每次递归前后两个坐标相遇的点
while(i<j&&a[j]>=temp)//从右向左找到第一个比temp小的值
{
j--;
}
if(i<j)
{
a[i]=a[j];//将a[j]的值填入a[i],此时a[j]被挖空
}
while(i<j&&a[i]<=temp)//从左到右找到第一个比temp大的值
{
i++;
}
if(i<j)
{
a[j]=a[i];//将这个比temp小的值填入a[j],此时a[i]被挖空
}
}
a[i]=temp;//每次循环结束时,a[i]都处于挖空的状态,将temp填入a[i]
quickSort(a, startIndex, i-1);
quickSort(a, i+1, endIndex);
}
return a;
}
代码中,外面的while循环,每次执行时,控制的是前后两个‘指针’,指针相遇时跳出循环,内循环负责查找元素,并赋值。每次递归在理想状态下两个内循环构与临时变量temp以及a[i]形成一次三个元素的交换(4,5,2,6.数组依次变成2,5,2,6; 2,5,5,6; 2,4,5,6.)。当然交换的次数可能大于三次,可能是两个元素的交换(如3,2,4,5只需要3和2交换位置),也可能只有一次循环体外的赋值操作(数组本身就是有序的)。
第三种方式最容易理解,采用前后两个‘指针’,后面的指针先移动,找到第一个小于基准数的元素,前面的指针后移动,找到第一个大于基准数的元素,交换着两个‘指针’所指的元素。直到两个指针相遇,交换当前元素与基准数。注意一定要后面的指针先移动
public static int [] quickSort2(int a[],int startIndex,int endIndex){
if(startIndex<endIndex){
int i=startIndex;
int j=endIndex;
int temp=a[i];//将a[i]存储到临时变量里面
int t;//交换用的临时变量
while(i<j){
while(i<j&&a[j]>=temp){//从右边开始找到第一个小于temp的值
j--;
}
while(i<j&&a[i]<=temp){//从左边开始找到第一个大于temp的值
i++;
}
if(i<j){//交换两个值
t=a[j];
a[j]=a[i];
a[i]=t;
}
}
a[startIndex]=a[i];//跳出循环时,此时的i和j相等,交换基准数与a[i]的值。
a[i]=temp;
quickSort2(a, startIndex, i-1);
quickSort2(a, i+1, endIndex);
}
return a;
}
有人说“第三种方式,不是快速排序,快速排序每次交换都是跟基准数交换”。对此观点,很不赞同,难道非要和书上一模一样的才是快速排序吗,快速排序的中心思想就是找到基准数的最终位置,再用二分思想和递归对左右两个数组进行排序。这种方式并没有违背算法的中心思想,所以应该是正确的,而且交换的次数会比传统方式的次数少。