三、排序_04 &数组中第k小的数(笔记)

同样还是先上代码:

import java.util.Arrays;
import java.util.Random;

public class A010_数组中第K小的元素 {

	public static void main(String[] args) {
		int len = 10;
		int max = 20;
		int k = 3;
		int[] arr = getRandomArr(len, max);
		System.out.println(Arrays.toString(arr));
		int idxValue = selectK(arr, 0, len - 1, k);
		System.out.println(idxValue);
	}

	public static int selectK(int[] arr, int l, int r, int k) {
		int idx = partion(arr, l, r);
		int qk = idx - l + 1;// 为什么要-L+1
		if (qk == k)
			return arr[idx];
		else if (qk > k)
			return selectK(arr, l, idx - 1, k);
		else
			return selectK(arr, idx + 1, r, k - qk);
	}

	public static int partion(int[] arr, int left, int right) {
		int mid = (left + right) / 2;
		int midValue = -1;
		if (arr[left] <= arr[mid] && arr[left] >= arr[right]) {
			midValue = left;
		} else if (arr[right] <= arr[mid] && arr[right] >= arr[left]) {
			midValue = right;
		} else
			midValue = mid;
		int t = arr[midValue];
		arr[midValue] = arr[left];
		arr[left] = t;

		int head = arr[left];
		int L = left;
		int R = right;
		while (L < R) {
			while (L < R && head < arr[R])
				R--;
			while (L < R && head >= arr[L])
				L++;
			t = arr[L];
			arr[L] = arr[R];
			arr[R] = t;
		}
		arr[left] = arr[R];
		arr[R] = head;
		return R;
	}

	public static int[] getRandomArr(int len, int max) {
		int[] arr = new int[len];
		Random ran = new Random();
		for (int i = 0; i < len; i++) {
			arr[i] = ran.nextInt(max) + 1;
		}
		return arr;
	}
}

在这里插入图片描述
还是同样的套路生成随机数组,随后调用selectK函数,这个函数的作用是直接返回那个我们要找的第k小的数;
进入selectK函数后首先调用的是partion函数,该方法的作用与三点中值法的快排作用类似,差别就是,我在之前快排的时候返回值是void,这里是返回下标idx,idx返回的就是排序后,主元的那个值得下标也就是说,现在的idx,左边都是小于它的,右边都是大于它的,而qk就是第几个元素,如果qk比要求的k大,那就去idx的左边找,如果qk比要求的k的值小,那么就要去idx的右边找,然后这里需要注意的是,k是要减去qk的,因为求的是第k个元素,在右边的话,长度肯定是比整体长度要小的,所以新的k的值也要整体缩小,所以需要传入k-qk的长度,比如要求的是第五个小的,然后这个数组中一共有6个元素,那么第一次partion函数走下来后,idx是在左边的,那么这个时候,就要去右边去找,那么这个时候的第“零”个元素,其实就是idx+1了,那么从这个开始第第k的元素,就是k-qk了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值