1-题目-取中位数

一个数据流中,随时可以取得中位数
image.png

  1. import java.util.Arrays;
  2. import java.util.Comparator;
  3. import java.util.PriorityQueue;
  4. public class Code06_MadianQuick {
  5. public static class MedianHolder {
  6. // 大顶堆
  7. private PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(new MaxHeapComparator());
  8. // 小顶堆
  9. private PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>(new MinHeapComparator());
  10. // 调整两个堆的数据,使其保持相对平衡状态(两个堆的数据的个数相差小于2)
  11. private void modifyTwoHeapsSize() {
  12. if (this.maxHeap.size() == this.minHeap.size() + 2) {
  13. this.minHeap.add(this.maxHeap.poll());
  14. }
  15. if (this.minHeap.size() == this.maxHeap.size() + 2) {
  16. this.maxHeap.add(this.minHeap.poll());
  17. }
  18. }
  19. // 数据流的值应该放到哪个堆中
  20. // 小的值放到大顶堆中
  21. // 大的值放到小顶堆中
  22. public void addNumber(int num) {
  23. if (maxHeap.isEmpty() || num <= maxHeap.peek()) {
  24. maxHeap.add(num);
  25. } else {
  26. minHeap.add(num);
  27. }
  28. modifyTwoHeapsSize();
  29. }
  30. // 数据流的数据在都放到堆中后,便通过大顶堆和小顶堆的堆顶来计算中位数
  31. public Integer getMedian() {
  32. int maxHeapSize = this.maxHeap.size();
  33. int minHeapSize = this.minHeap.size();
  34. if (maxHeapSize + minHeapSize == 0) {
  35. return null;
  36. }
  37. Integer maxHeapHead = this.maxHeap.peek();
  38. Integer minHeapHead = this.minHeap.peek();
  39. if (((maxHeapSize + minHeapSize) & 1) == 0) {
  40. return (maxHeapHead + minHeapHead) / 2;
  41. }
  42. return maxHeapSize > minHeapSize ? maxHeapHead : minHeapHead;
  43. }
  44. }
  45. // 大顶堆比较器
  46. public static class MaxHeapComparator implements Comparator<Integer> {
  47. @Override
  48. public int compare(Integer o1, Integer o2) {
  49. if (o2 > o1) {
  50. return 1;
  51. } else {
  52. return -1;
  53. }
  54. }
  55. }
  56. // 小顶堆比较器
  57. public static class MinHeapComparator implements Comparator<Integer> {
  58. @Override
  59. public int compare(Integer o1, Integer o2) {
  60. if (o2 < o1) {
  61. return 1;
  62. } else {
  63. return -1;
  64. }
  65. }
  66. }
  67. // for test 生产随机数组
  68. public static int[] getRandomArray(int maxLen, int maxValue) {
  69. int[] res = new int[(int) (Math.random() * maxLen) + 1];
  70. for (int i = 0; i != res.length; i++) {
  71. res[i] = (int) (Math.random() * maxValue);
  72. }
  73. return res;
  74. }
  75. // for test, this method is ineffective but absolutely right 通过排序计算中位数,用于最后的判断
  76. public static int getMedianOfArray(int[] arr) {
  77. int[] newArr = Arrays.copyOf(arr, arr.length);
  78. Arrays.sort(newArr);
  79. int mid = (newArr.length - 1) / 2;
  80. if ((newArr.length & 1) == 0) {
  81. return (newArr[mid] + newArr[mid + 1]) / 2;
  82. } else {
  83. return newArr[mid];
  84. }
  85. }
  86. public static void printArray(int[] arr) {
  87. for (int i = 0; i != arr.length; i++) {
  88. System.out.print(arr[i] + " ");
  89. }
  90. System.out.println();
  91. }
  92. public static void main(String[] args) {
  93. boolean err = false;
  94. int testTimes = 200000;
  95. for (int i = 0; i != testTimes; i++) {
  96. int len = 30;
  97. int maxValue = 1000;
  98. int[] arr = getRandomArray(len, maxValue);
  99. MedianHolder medianHold = new MedianHolder();
  100. for (int j = 0; j != arr.length; j++) {
  101. medianHold.addNumber(arr[j]);
  102. }
  103. if (medianHold.getMedian() != getMedianOfArray(arr)) {
  104. err = true;
  105. printArray(arr);
  106. break;
  107. }
  108. }
  109. System.out.println(err ? "Oops..what a fuck!" : "today is a beautiful day^_^");
  110. }
  111. }