Java代码【快速排序】详解

目录

  • 概要
  • 原理
    • 双边循环法
  • 双边循环法代码实现
  • 单边循环法
  • 单边循环法代码实现
  • 非递归实现
  • 个人总结

概要

快速排序是一种交换排序,通过元素之间的比较和交换位置来达到排序目的。

原理

在每一轮挑选一个基准元素,并让其他比它大的元素移动到数列一边,比它小的元素移动到数列的另一边,从而把数列拆解成两部分。
这种思路叫做:分治法
Java代码【快速排序】详解_第1张图片

代码中方法说明:

  • quickSort方法通过递归方式,实现分而治之的思想。
  • partition方法实现元素交换,让数列中的元素依据自身大小,分别交换到基准元素的左右两边

双边循环法

4 7 6 5 3 2 8 1

从数组的两边交替遍历元素
Java代码【快速排序】详解_第2张图片
Java代码【快速排序】详解_第3张图片
简单概括一下以上过程:

  1. 指定基准元素、left索引、right索引。将第一个元素指定为基准元素pivot,最左边标记为left,最右边标记为right。
  2. 从right开始,与pivot比较,right指向比pivot小或相等的数,否则right一直向左移动
  3. 切换到left,left指向比pivote大的数,否则left一直向右移动
  4. 经过2、3过程后,将right和left位置互换,再继续执行2、3步骤。
  5. 当right移动到和left重合,停止。此时将left指向的数与pivot指向的数位置互换
  6. 以pivot为分界点,对左侧数列和右侧数列分别进行1~6部操作,进行下一轮排序。

双边循环法代码实现

import java.util.Arrays;

public class Array {
     
    //快速排序
    public static void quickSort(int[] arr,int startIndex,int endIndex){
     
    //递归结束条件:startIndex大于或等于endIndex时
        if(startIndex >= endIndex){
     
            return;
        }
        //得到基准元素位置
        int pivotIndex = partition(arr,startIndex,endIndex);
        //根据基准元素,分成两部分进行递归排序
        quickSort(arr,startIndex,pivotIndex - 1);
        quickSort(arr,pivotIndex + 1,endIndex);
    }
    /**
	*分治(双边循环法)
	*@param arr			待交换的数组
	*@param startIndex	起始下标
	*2param endIndex	结束下标
	*/
    public static int partition(int[] arr,int startIndex,int endIndex){
     
    //取第一个位置(也可以选择随机位置)的元素作为基准元素
        int pivot = arr[startIndex];
        int left = startIndex;
        int right = endIndex;

        while (left != right) {
     
        //控制right指针比较并左移
            while (left < right && arr[right] > pivot){
     
                right --;
            }
		//控制left指针比较并右移
            while (left < right && arr[left] <= pivot){
     
                left ++;
            }
		//交换left和right指针指向的元素
            if(left < right) {
     
                int temp = arr[left];
                arr[left] = arr[right];
                arr[right] = temp;
            }
           System.out.println(Arrays.toString(arr));
        }
        //pivot和指针重合点交换
        arr[startIndex] = arr[left];
        arr[left] = pivot;

        return left;
    }

    public static void main(String[] args) {
     
        int[] arr = {
     4,7,6,5,3,2,8,1};
        quickSort(arr,0,arr.length -1);
        System.out.println(Arrays.toString(arr));
    }
}

每一轮排序情况大致如下:
Java代码【快速排序】详解_第4张图片
这里需要注意的是

这里需要注意的是左右与pivot比较时候的符号,rjgth > pivot,left <= pivot

 //控制right指针比较并左移
 while (left < right && arr[right] > pivot){
     
     right --;
}
//控制left指针比较并右移
while (left < right && arr[left] <= pivot){
     
     left ++;
}

双边循环法虽然更加直观,但是代码相对繁琐,单边循环法则简单得多。

单边循环法

4 7 3 5 6 2 8 1

从数组的一遍对元素进行遍历和交换。

Java代码【快速排序】详解_第5张图片
Java代码【快速排序】详解_第6张图片
简单概括一下以上过程:

  1. 设置基准元素pivot、设置mark。pivot为第一个元素,mark指向起始位置。
  2. 从pivot下一个位置开始遍历元素,若元素大于pivot则继续,若元素小雨pivot,则mark右移一位,然后此元素和mark指向的元素换位。

单边循环法代码实现

与双边循环比较只是partition方法实现不同。

import java.util.Arrays;

public class Array {
     
    //快速排序
    public static void quickSort(int[] arr,int startIndex,int endIndex){
     
        if(startIndex >= endIndex){
     
            return;
        }
        int pivotIndex = partition(arr,startIndex,endIndex);
        quickSort(arr,startIndex,pivotIndex - 1);
        quickSort(arr,pivotIndex + 1,endIndex);
    }
    
    /**
	*分治(双边循环法)
	*@param arr			待交换的数组
	*@param startIndex	起始下标
	*2param endIndex	结束下标
	*/
    public static int partition(int[] arr,int startIndex,int endIndex){
     
        int pivot = arr[startIndex];
        int mark = startIndex;

        for(int i = startIndex+1;i <= endIndex;i++){
     
            if(arr[i] < pivot){
     
                mark++;
                int temp = arr[mark];
                arr[mark] = arr[i];
                arr[i] = temp;
            }
        }
        arr[startIndex] = arr[mark];
        arr[mark] = pivot;
        return mark;
    }

    public static void main(String[] args) {
     
        int[] arr = {
     4,7,6,5,3,2,8,1};
        quickSort(arr,0,arr.length -1);
        System.out.println("最后排序结果是:"+Arrays.toString(arr));
    }
}

Java代码【快速排序】详解_第7张图片

非递归实现

待更新

个人总结

  • 快速排序思想:
    找基准,定左右,由外向内两侧比,大小元素分两边,
    重合与基换位置,分治递归再一遍
  • 快速排序复杂度:
    O(nlgn)—O(nlgn)—O(n^2)—O(1)[平均—最好—最坏—空间复杂度]
  • 快速排序特点:不稳定
  • 快速排序代码框架:
    双边(个人使用的是双边)
递归:quickSort(){
     
	若左右指针重合,结束递归
	由partition()找到基准元素
	左侧递归:quickSort()
	右侧递归:quickSort()
}
找基准元素partition()
	选取随机基准元素pivot(一般取第一个元素)、left、right
	左右索引不重合时{
     
		右侧:left<right且right元素比pivot大,right指针左移
		左侧:left<right且left元素比pivot大,left指针右移

		否则就是 左边元素大于pivot,右边元素小与pivot,就换位
	}
	pivot和指针重合点交换
	return left

单边

待编辑

非递归

待编辑

你可能感兴趣的:(《小灰的算法之旅》笔记,#,排序,Java,java,快速排序,分治递归)