思路:
1、快排思想
2、小顶堆或者大顶堆(使用优先级队列PriorityQueue实现小顶堆)
3、top k问题可采用类似解法。
代码:
package com.my.test.datastructure.array;
import java.util.Comparator;
import java.util.PriorityQueue;
/**
* 无序数组的中位数
*
* 获取排序后的第size/2(size为偶数),(size+1)/2(size为奇数)个元素
* 对应下标为(size-1)/2
*
*/
public class ArrMidNum
{
/**
* 快排思想-直至mid为(size-1)/2
*
*/
public static int getMidNum(int[] arr) {
if (arr == null || arr.length <= 0) {
return -1;
}
int size = arr.length;
int targetMid = (size-1)/2;
int low = 0;
int high = size - 1;
int mid = getMid(arr, low, high);
while (mid != targetMid) {
if (mid < targetMid) {
mid = getMid(arr, mid + 1, high);
} else {
mid = getMid(arr, low, mid - 1);
}
}
return arr[mid];
}
/**
* 快排思想-一趟排序
*/
private static int getMid(int[] arr, int low, int high) {
int base = arr[low];
while (low < high) {
// 判断条件必须加=场景,为<= 不能为<,否则数组中有相同数据时,会一直循环
while (low < high && base <= arr[high]) {
high--;
}
arr[low] = arr[high];
// 判断条件必须加=场景,为>= 不能为>,否则数组中有相同数据时,会一直循环
while (low < high && base >= arr[low]) {
low++;
}
arr[high] = arr[low];
}
arr[low] = base;
return low;
}
/**
* 堆排序,组建一个(size+1)/2大小的最小堆 ,取到top (size+1)/2个大的值,则堆顶元素即为中位数
*
* 先取前(size+1)/2个元素,组成最小堆,剩下的元素和堆顶比较,比堆顶小则忽略,比堆顶大则交换,然后重组最小堆
*/
public static int getMidNumByMinHeap(int[] arr) {
if (arr == null || arr.length <= 0) {
return -1;
}
// 内部实现了最小堆(默认自然序)
PriorityQueue<Integer> queue = new PriorityQueue<>();
// 初步组建最小堆
int size = arr.length;
int heapSize = (size + 1) / 2;
for (int i=0; i<heapSize; i++) {
queue.offer(arr[i]);
}
// 比较余下元素,比堆顶大则替换堆顶元素为新值
for (int j=heapSize;j<size;j++) {
int temp = arr[j];
// 当前元素比堆顶大 则删除堆顶元素,把当前元素加入堆
if (queue.peek() < temp) {
queue.poll();
queue.offer(temp);
}
}
// 返回堆顶元素
return queue.peek();
}
/**
* 堆排序,组建一个(size+1)/2大小的最大堆 ,取到top (size+1)/2个小的值,则堆顶元素即为中位数
*
* 先取前(size+1)/2个元素,组成最大堆,剩下的元素和堆顶比较,比堆顶大则忽略,比堆顶小则交换,然后重组最大堆
*/
public static int getMidNumByMaxHeap(int[] arr) {
if (arr == null || arr.length <= 0) {
return -1;
}
// 内部实现了最大堆(实现自定义从大到小排序)
PriorityQueue<Integer> queue = new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2)
{
return o2 - o1;
}
});
// 初步组建最大堆
int size = arr.length;
int heapSize = (size + 1) / 2;
for (int i=0; i<heapSize; i++) {
queue.offer(arr[i]);
}
// 比较余下元素,比堆顶小则替换堆顶元素为新值
for (int j=heapSize;j<size;j++) {
int temp = arr[j];
// 当前元素比堆顶大 则删除堆顶元素,把当前元素加入堆
if (queue.peek() > temp) {
queue.poll();
queue.offer(temp);
}
}
// 返回堆顶元素
return queue.peek();
}
public static void main(String[] args)
{
int[] arr = {4,5,6,1,2,0,3,7,8,9,10,1,1,1,1,1,1};
System.out.println(getMidNum(arr));
int[] arr1 = {4,5,6,1,2,0,3,7,8,9,10,1,1,1,1,1,1};
System.out.println(getMidNumByMinHeap(arr1));
int[] arr2 = {4,5,6,1,2,0,3,7,8,9,10,1,1,1,1,1,1};
System.out.println(getMidNumByMaxHeap(arr2));
}
}
参考:
无序数组中位数:https://blog.csdn.net/oneday_789/article/details/76681764