数据结构排序算法之快速排序的两种实现方法加完整注释及测试

package Sort;

import java.text.SimpleDateFormat;
import java.util.Date;

public class QuickSort {

    public static void main(String[] args) {

        //测试 quickSort
        /*int [] arr = new int[100000];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * 100000);
        }
        //print(arr);
        Date date1 = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd hh-mm-ss");
        String strDate1 = simpleDateFormat.format(date1);
        System.out.println("排序前的时间是"+strDate1);

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

        Date date2 = new Date();
        //SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat("yyyy-mm-dd hh-mm-ss");
        String strDate2 = simpleDateFormat.format(date2);
        System.out.println("排序后的时间是"+strDate2);
*/

         //System.out.println("---------------");
       // print(arr);

        //测试 quickSort02
        int [] arr = new int[29];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * 50);
        }
        print(arr);
        quickSort02(arr,0, arr.length - 1);
        System.out.println("---------------");
        print(arr);


    }

    //快速排序:
    //思路1:使用中间值作为基准,当且仅当 l < r ,(同时)从左边扫描,找到左边第一个大于等于基准值的数,周到右边第一个小于等于基准值的数
    //先判断是否需要交换,如果l < r,则交换它们,否则l >= r 说明左边的已经全部 < 基准值, 右边的全部 > 基准值,否则重复以上操作.
    //交换之后,判断是否需要前移一位或者后移一位,防止进入死循环。如 5 5 5 (交换之后)--->5 5 5 如果不根据条件,前移一位或者后移一位
    //则方法进入无限循环。
    //退出循环之后,判断是否需要进行左递归(区间[left,r])和右递归(区间[l,right])
    public static void quickSort(int [] arr, int left, int right){
        int l = left;
        int r = right;
        int pivot = arr[(left + right) / 2];//使用中间值作为基准
        int temp = 0;

        //当且仅当 l < r
        while (l < r){
            //同时)从左边扫描,找到左边第一个大于等于基准值的数,周到右边第一个小于等于基准值的数
            //找到左边第一个大于等于基准值的数的下标
            while (arr[l] < pivot){
                l += 1;
            }
            //找到右边第一个小于等于基准值的数的下标
            while (arr[r] > pivot){
                r -= 1;
            }

            //否则l >= r 说明左边的已经全部 < 基准值, 右边的全部 > 基准值
            //判断l 和 r 的此时值
            //l >= r 此时左边 已经没有大于基准值的数, 右边没有小于基准值的数,本次分组交换退出
            if(l >= r){
                break;
            }
            //如果l < r,则交换它们
            //否则,交换 l 和 r 的值
            temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;

            交换之后,判断是否需要前移一位或者后移一位,防止进入死循环。
            // 如 5 5 5 (交换之后)--->5 5 5 如果不根据条件,前移一位或者后移一位

            //这时再判断交换之后arr[l] 的值 与 pivot的值的情况,如果arr[l] == pivot,避免死循环
            if(arr[l] == pivot){
                r -= 1;
            }
            //这时再判断交换之后arr[r] 的值 与 pivot的值的情况,如果arr[r] == pivot,避免死循环
            if(arr[r] == pivot){
                l += 1;
            }
        }
        
        //当一次分割交换结束之后,避免陷入死循环
        if(l == r){
            l += 1;
            r -= 1;
        }

        //向左递归,左递归的区间是[left,r]
        if(left < r){
            quickSort(arr,left,r);
        }
        // //向右递归,右递归的区间是[l,right]
        if(right > l){
            quickSort(arr,l,right);
        }
    }

    public static void quickSort02(int [] arr, int low, int high){
        if(low < high){
            int index = getIndex(arr, low, high);
            quickSort02(arr,low,index-1);
            quickSort02(arr,index+1,high);
        }
    }
/*
        快速排序思路2:使用数组第一个元素作基准值,用 tmp 保存起来
 */
    public static int getIndex(int []arr,int low,int high){
        int tmp = arr[low];
        //首先从后往前遍历
        while (low < high){

            //首先 从后 往前 遍历,遇到第一个 大于 基准值的时候停下
            while (low < high && arr[high] >= tmp){
                high--;
            }

            //把第一个大于基准值的 赋值给low,第一次即赋值给基准值,因为基准值已经另外保存
            arr[low] = arr[high];

            //然后开始 从前往后 开始扫描,找到第一个大于基准值是停下
            while (low < high && arr[low] <= tmp){
                low++;
            }
            //停下之后,找到一个大于基准值的数,把它交换给arr[high], 因为前面arr[high]的原值已经被交换到arr[low]
            arr[high] = arr[low];

            //这时,如果 low < high , 则继续从后往前 重复上面两个 内层while循环
        }

        //退出循环后,low == high,即基准值要插入的地方
        arr[low] = tmp;
        //返回下一次开始 分割 的下标low--->index,分成[low,index-1],[index+1,high],
        //注意:返回值后,此时的low high 是未变化的,因为值传递
        return low;
    }

    public static void print(int [] array){
        for (int i = 0; i < array.length; i++) {
            System.out.printf("%d ",array[i]);
            /*if(i % 50 == 0){
                System.out.println();
            }*/
        }
        System.out.println();
        // System.out.println(count);
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值