快速排序(Quick Sort/QKSORT)Java程序代码——包含四种基准值选取(AC代码)

快速排序代码讲解

1. 导入必要的包
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Random;
  • BufferedReaderInputStreamReader 用于从标准输入读取数据(为什么不用Scanner,因为慢啊!!!!!!).
  • Random 用于生成随机数,以随机选择基准值.
2. 主类和主函数
public class Main {
    private static Random r = new Random();
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        // 获取数据
        int n = Integer.parseInt(br.readLine());
        int[] arr = new int[n];
        String[] strs = br.readLine().split(" ");
        for (int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(strs[i]);
        }
        // 算法计算
        long start = System.currentTimeMillis();
        solution(arr);
        System.out.println("总用时:" + (System.currentTimeMillis() - start) + "ms");//把这行注释了就可以通过acwing上的题
        // 输出结果
        for (int i : arr) {
            System.out.print(i + " ");
        }
        br.close();
    }
}
  • 数据输入:从标准输入读取数组长度 n 和数组元素,存储到数组 arr 中.
  • 排序和计时:调用 solution 函数进行快速排序,并记录排序所用的时间.
  • 结果输出:输出排序后的数组和总用时.
3. 排序函数 solution
private static void solution(int[] arr) {
    int len = arr.length;
    quickSort(arr, 0, len - 1);
}
  • 调用 quickSort 函数对数组进行快速排序,传入数组、起始索引 0 和结束索引 len - 1.
4. 快速排序函数 quickSort
private static void quickSort(int[] arr, int left, int right) {
    if (left >= right) {
        return;
    }
    int i = left - 1;
    int j = right + 1;
    // 基准点的四种选取方式
    // int x = arr[left]; // 不推荐:极端数据下会栈会特别深
    // int x = arr[right]; // 不推荐:极端数据下会栈会特别深
    // int x = arr[left + ((right - left) >> 1)]; // 中立:极端数据下栈会特别深,但大多数情况下速度最快
    int x = arr[left + r.nextInt(right - left)]; // 推荐:极端数据下处理的性能依旧是 O(nlogn)

    while (i < j) {
        // 从左往右找到第一个不小于 x 的数
        while (arr[++i] < x);
        // 从右往左找到第一个不大于 x 的数
        while (arr[--j] > x);
        if (i < j) {
            swap(arr, i, j);
        }
    }

    // 分类处理
    if (i == j) {
        // 相遇在与基准值同值的位置: 忽略基准值,从两边取值
        quickSort(arr, left, i - 1);
        quickSort(arr, i + 1, right);
    } else {
        // i 在 j 的右侧
        // 用 j 分割的情况
        // quickSort(arr, left, j); // j 左侧的所有值(包括 j)都不大于基准值 x
        // quickSort(arr, j + 1, right); // j 右侧的所有值都不小于基准值 x

        // 用 i 分割的情况
        quickSort(arr, left, i - 1); // i 左侧的所有值都不大于基准值 x
        quickSort(arr, i, right); // i 右侧的所有值(包括 i)都不小于基准值 x
    }
}
  • 基准值选择:这里选择了随机选择基准值的方式,以避免极端情况下的性能退化.
  • 分区操作:使用双指针 ij 进行分区,i 从左向右移动,j 从右向左移动,直到 ij 相遇.
  • 递归排序:根据 ij 的位置,递归地对左右两部分进行排序.
5. 交换函数 swap
private static void swap(int[] arr, int i, int j) {
    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
  • 交换数组中索引 ij 处的元素.

完整代码

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Random;

public class Main {
	private static Random r = new Random();//随机选取用
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		//获取数据
		int n = Integer.parseInt(br.readLine());
		int[] arr = new int[n];
		String[] strs = br.readLine().split(" "); 
		for(int i = 0; i < n; i++) {
			arr[i] = Integer.parseInt(strs[i]);
		}
		//算法计算
		long start = System.currentTimeMillis();
		solution(arr);
		System.out.println("总用时:"+(System.currentTimeMillis() - start)+"ms");//把这行注释了就可以通过acwing上的题
		//输出结果
		for(int i : arr) {
			System.out.print(i + " ");
		}
		br.close();
	}

	private static void solution(int[] arr) {
		int len = arr.length;
		quickSort(arr,0,len-1);
	}

	private static void quickSort(int[] arr, int left, int right) {
		if(left >= right) {
			return;
		}
		int i = left - 1;
		int j = right + 1;
		
		/*基准点的四种选取方式*/
//		int x = arr[left]; //不推荐:极端数据(有序)下会栈会特别深(二叉树变单链表的那种)
//		int x = arr[right];//不推荐:极端数据(有序)下会栈会特别深(二叉树变单链表的那种)
//		int x = arr[left + ((right - left) >> 1)];//中立:极端数据(即每次中间的基准数都被安排成了这一段的最值)下栈会特别深,但大多数情况下是速度最快的
		int x = arr[left + r.nextInt(right - left)];//推荐:极端数据下处理的性能依旧是O(nlogn)

		
		while(i < j) {
			//从左往右找到第一个不小于x的数
			while(arr[++i] < x);
			//从右往左找到第一个不大于x的数
			while(arr[--j] > x);
			if(i < j) {
				swap(arr,i,j);
			}
		}

		//这里做分类主要是为了避免当i和j相遇在第1个数和第n个数时的越界现象
		if(i == j) {
			/*相遇在与基准值同值的位置:忽略基准值,从两边取值*/
			quickSort(arr,left,i-1);
			quickSort(arr,i+1,right);
		}else {
			/*i在j的右侧*/
			
			/*用j分割的情况*/
//			quickSort(arr, left, j);//j左侧的所有值(包括j)都不大于基准值x
//			quickSort(arr, j+1, right);//j右侧的所有值都不小于基准值x
			
			/*用i分割的情况*/
			quickSort(arr, left, i-1);//i左侧的所有值都不大于基准值x
			quickSort(arr, i, right);//i右侧的所有值(包括i)都不小于基准值x
		}
	}

	private static void swap(int[] arr, int i, int j) {
		int temp = arr[i];
		arr[i] = arr[j];
		arr[j] = temp;
	}
}

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值