快速排序算法——java

  思想:快速排序算法利用分治思想,通过一个基准元素将待排数组分成左右两部分,左边部分均比基准元素小,右边部分均比基准元素大,然后对左右两部分分别递归调用快速排序算法,最终实现排序的目的。

  面试中较为常见的算法之一就是快速排序,快速排序在实际排序应用中也是最好的选择,因为它的平均性能非常好,它的期望复杂度为nlgn,另外,它还是一种稳定的排序方法。快速排序利用分治思想,将待排序数组分成左右两个部分,然后对其分别递归调用快速排序算法。

  下面通过一个例子介绍快速排序算法的思想,假设要对数组a[10]={6,1,2,7,9,3,4,5,10,8}进行排序,首先要在数组中选择一个数作为基准值,这个数可以随意选择,在这里,我们选择数组的第一个元素a[0]=6作为基准值,接下来,我们需要把数组中小于6的数放在左边,大于6的数放在右边,怎么实现呢?

  我们设置两个“哨兵”,记为“哨兵i”和“哨兵j”,他们分别指向数组的第一个元素和最后一个元素,即i=0,j=9。首先哨兵j开始出动,哨兵j一步一步地向左挪动(即j–),直到找到一个小于6的数停下来。接下来哨兵i再一步一步向右挪动(即i++),直到找到一个数大于6的数停下来。

 

  最后哨兵j停在了数字5面前,哨兵i停在了数字7面前。此时就需要交换i和j指向的元素的值。

 

  交换之后的数组变为a[10]={6,1,2,5,9,3,4,7,10,8}:

 

  第一次交换至此结束。接下来,由于哨兵i和哨兵j还没有相遇,于是哨兵j继续向前,发现比6小的4之后停下;哨兵i继续向前,发现比6大的9之后停下,两者再进行交换。交换之后的数组变为a[10]={6,1,2,5,4,3,9,7,10,8}。

 

  第二次交换至此结束。接下来,哨兵j继续向前,发小比6小的3停下来;哨兵i继续向前,发现i==j了!!!于是,这一轮的探测就要结束了,此时交换a[i]与基准的值,数组a就以6为分界线,分成了小于6和大于6的左右两部分:a[10]={3,1,2,5,4,6,9,7,10,8}。

 

  至此,第一轮快速排序完全结束,接下来,对于6左边的半部分3,1,2,5,4,执行以上过程;对于6右边的半部分9,7,10,8,执行以上过程,直到不可拆分出新的子序列为止。最终将会得到这样的序列:1 2 3 4 5 6 7 8 9 10,到此,排序完全结束。

代码如下:

package 快速排序;

 

import java.util.Arrays;

 

/**

 * 快速排序

 * 思路:快速排序算法利用分治思想,通过一个基准元素将待排数组分成左右两部分,左边部分均比基准元素小,右边部分均比基准元素大,然后对左右两部分分别递归调用快速排序算法,最终实现排序的目的。

 */

public class quickSort2 {

public static void main(String[] args) {

//定义一个数组

int[] arr = {3,4,6,5,3,1,7,2,8,9};

 

//调用方法,快速排序

quickSort(arr);

 

//打印数组

System.out.println(Arrays.toString(arr));

}

 

//快速排序对外提供的访问接口

public static void quickSort(int[] arr) {

quickSort(arr,0,arr.length-1);

}

 

private static void quickSort(int[] arr, int low, int high) {

if(low >= high){

return;

}

//进行一次排序,并返回排序后基准元素所在的下标

int pivotIndex = partition(arr,low,high);

//递归调用快速排序算法

quickSort(arr, low, pivotIndex-1);

quickSort(arr, pivotIndex+1,high);

}

 

//分治思想分割数组

private static int partition(int[] arr, int low, int high) {

 int i = low;//让a[i]作为基准元素

         while(low<high){

          //从右至左遍历出比基准元素小的值(等于的情况要么给右边,要么给左边)

             while(low<high&&arr[high]>=arr[i]){

                     high--;

             }

             //从左至右遍历出比基准元素大的值

             while(low<high&&arr[low]<arr[i]){

                     low++;

             }

             //将右边找到的比基准元素大的值与左边找到的比基准元素小的值交换位置

             int p = arr[low];

             arr[low] = arr[high];

             arr[high] = p;

         }

         //最终的结果low与high重合,且这个值一定小于等于基准元素

         //(因为先从右到左找大值,再从左到右找小值,所以这里是arr[low];

         //如果反过来,这里就是arr[low-1])

         int p = arr[low];

         arr[low] = arr[i];

         arr[i] = p;

         

         return low;

}

}