无序数组的中位数(PriorityQueue小顶堆解法)(Java)

思路:

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

                             https://www.cnblogs.com/shizhh/p/5746151.html

猜你喜欢

转载自blog.csdn.net/zangdaiyang1991/article/details/88641830