快速排序算法笔记
快速排序算法图解
假设原始数组 int [ ] arr = new int [7]如下:
选取最左边下标为0的元素 4 为基准值,使小于分界值的元素放到数组的左边,大于分界值的元素放到数组的右边。算法实现如下
首先定义两个索引 left 和 right分别指向数组第一个元素(此处为0)和数组最右端+1(此处为7,注意:此时,right索引已超数组长度)。
第一步:从右往左搜索,right 依次递减,找到一个比基准值小的数( arr [ - -right ] < 4 ) 为止。当right 递减 5 时,找到 。
第二步,从左往右搜索,left 依次递加,找到一个比基准值 大的数 (arr[ ++ left ] > 4 ) 为止。当 left 递加到 1 时,找到 。
第三步,交换 left , right 索引对应的值。得到数组 [ 4,1,2,3,7,5,6 ] 。然后 right 索引继续递减,寻找比基准值4 小的数。当 right 递减到 3 时,找到。
第四步, left 索引继续依次递加,寻找比基准值4大的数,但是未找到,就遇见 right 索引了,此时,数组中所有数都已经被寻找过一遍了,left索引不再继续递加,与 right 索引指向同一个位置。
第五步,交换基准值4 与 right 、 left 索引指向的3 的位置,得到如下数组。
以 4 为分界值将数组切分为两部分,得到数组1,数组2 。
同时4的索引设为 x (此处为3)。
第一个部分数组的索引为 0 到 x-1 (此处为2)。同理,选最左边下标为 0 的元素 3 为基准值,再次按上述方法进行分组。此时, right = 2 = left 。将基准值 3 和right、left一起指向的 2互换得到如下。
然后以3 分界线,将数组分为 [ 2,1]。因为3 右边无值。只能分成一个数组。
算法需要用到的几个方法
- 比较大小的方法
public boolean compare(int c,int d,int[] arr){
return arr[c]>arr[d];
}
- 交换元素的方法
public void exchange(int[] arr ,int a,int b ){
int temp=0;
temp=arr[a];
arr[a]=arr[b];
arr[b]=temp;
}
- 递归排序方法
public void sort(int[] arr,int l0,int r0){
if(l0>=r0) return;//如果输入数组的最小索引l0>r0,则排序无意义,直接返回
int bound = part(arr, l0, r0);//调用下面的数组分区方法(核心算法)
sort(arr,l0,bound-1);//将切分掉的两个数组递归调用sort()方法
sort(arr,bound+1,r0);
}
- 数组分区方法(核心算法)
public int part(int[] arr,int l0,int r0){
int left=l0;//将left索引设置为输入数组的索引最小值,不一定就是0
int right=r0+1;//将right索引设置为输入数组的索引最大值+1,此时arr[right]不存在
while(true){
//当right>left时,搜索才有意义。right索引自右往左找比基准值小的数。找到时,表达式为false结束循环
// 必须写成--right,因为一开始的 arr[right]不存在,写成right--会报异常
while (right>left&&compare(--right,l0,arr)){
}
//当left<right时,搜索才有意义,left索引自左往右找比基准值大的数,找到后,表达式为false结束循环
while(left<right&&compare(l0,++left,arr)){
}
//当left==right时,数组中所有元素均已找过一边,交换基准值与right索引指向的值。同时退出循环
if(right==left){
exchange(arr,l0,right);
break;
}else {//数组仍未遍历完,交换值,继续循环
exchange(arr,right,left);
}
}
//返回分界值的索引
return left;
}
代码演示
import java.util.Arrays;
public class Demo{
public void exchange(int[] arr ,int a,int b ){
int temp=0;
temp=arr[a];
arr[a]=arr[b];
arr[b]=temp;
}
public boolean compare(int c,int d,int[] arr){
return arr[c]>arr[d];
}
public void sort(int[] arr,int l0,int r0){
if(l0>=r0) return;
int bound = part(arr, l0, r0);
sort(arr,l0,bound-1);
sort(arr,bound+1,r0);
}
public int part(int[] arr,int l0,int r0){
int left=l0;
int right=r0+1;
while(true){
while (right>left&&compare(--right,l0,arr)){
}
while(left<right&&compare(l0,++left,arr)){
}
if(right==left){
exchange(arr,l0,right);
break;
}else {
exchange(arr,right,left);
}
}
return left;
}
public static void main(String[] args) {
QuickSort qp = new QuickSort();
int[] array={4,5,2,3,7,1,6};
qp.sort(array,0,array.length-1);
System.out.println(Arrays.toString(array));
}
}
输出结果:
[1,2,3,4,5,6,7]
快速排序的时间复杂度为O(nlogn)