如何修改Java代码实现数组的移动中位数并得到预期结果?
问题排查与解决方案
嘿,咱先揪出核心问题:你main方法里的Scanner用法完全搞错了,导致传给getMedians的数组根本不是你想要的{6, 12, 4, 5, 3, 8, 7},自然算不出正确结果。
具体来说,String.valueOf(adio)不会把数组元素转成逗号分隔的字符串,它返回的是数组的默认toString结果(比如[I@1b6d3586这种格式)。用Scanner读这个字符串,要么直接抛输入不匹配异常,要么读出来的数值完全不对,等于你给计算逻辑喂了个错误的数组,结果肯定跑偏。
修复步骤
直接砍掉错误的Scanner处理逻辑,把目标数组直接传给getMedians就行。而且你的中位数计算逻辑本身是对的,只要传对数组就能得到正确的运行中位数。
修改后的完整代码
import java.util.*; public class Movmedian { /** * 向堆中添加元素 */ public static void addNumber(int num, PriorityQueue<Integer> lowers, PriorityQueue<Integer> highers) { if (lowers.size() == 0 || num < lowers.peek()) { lowers.add(num); } else { highers.add(num); } } /** * 平衡两个堆的大小 */ public static void rebalance(PriorityQueue<Integer> lowers, PriorityQueue<Integer> highers) { PriorityQueue<Integer> biggerHeap = lowers.size() > highers.size() ? lowers : highers; PriorityQueue<Integer> smallerHeap = lowers.size() > highers.size() ? highers : lowers; if (biggerHeap.size() - smallerHeap.size() >= 2) { smallerHeap.add(biggerHeap.poll()); } } /** * 获取当前的中位数 */ public static double getMedian(PriorityQueue<Integer> lowers, PriorityQueue<Integer> highers) { PriorityQueue<Integer> biggerHeap = lowers.size() > highers.size() ? lowers : highers; PriorityQueue<Integer> smallerHeap = lowers.size() > highers.size() ? highers : lowers; if (biggerHeap.size() == smallerHeap.size()) { return ((double) biggerHeap.peek() + smallerHeap.peek()) / 2; } else { return biggerHeap.peek(); } } /** * 计算数组的运行中位数 * @param array 输入数组 */ public static double[] getMedians(int[] array) { // 大顶堆,存较小的一半元素(用Comparator.reverseOrder()替代匿名内部类,更简洁) PriorityQueue<Integer> lowHeap = new PriorityQueue<>(Comparator.reverseOrder()); // 小顶堆,存较大的一半元素 PriorityQueue<Integer> highHeap = new PriorityQueue<>(); double[] medians = new double[array.length]; for (int i = 0; i < array.length; i++) { int number = array[i]; addNumber(number, lowHeap, highHeap); rebalance(lowHeap, highHeap); medians[i] = getMedian(lowHeap, highHeap); System.out.println(medians[i]); // 打印每一步的运行中位数 } return medians; } /** * 主方法 */ public static void main(String[] args) { // 直接传入目标数组,去掉错误的Scanner处理 int[] adio = {6, 12, 4, 5, 3, 8, 7}; getMedians(adio); } }
运行结果验证
修改后运行代码,输出的运行中位数是:
6.0 9.0 6.0 5.5 5.0 5.5 6.0
这和你提到的@xtratic修改后的结果一致,说明你的计算逻辑没问题。如果你预期的是12.0 8.0 5.0 4.5 5.0 6.0,那大概率是对移动中位数的定义理解不同——当前代码实现的是逐个添加元素的运行中位数(每加入一个元素后,计算当前所有元素的中位数),而不是固定窗口大小的滑动中位数(比如窗口大小为3的滑动窗口)。如果需要滑动窗口中位数,那得调整逻辑,但当前代码的运行中位数实现是正确的。
补充:正确的控制台输入方式
如果你确实需要从控制台读取数组,正确的Scanner用法应该是这样:
public static void main(String[] args) { Scanner ini = new Scanner(System.in); System.out.print("请输入数组长度:"); int n = ini.nextInt(); int[] a = new int[n]; System.out.print("请输入数组元素(空格分隔):"); for(int i=0; i < n; i++){ a[i] = ini.nextInt(); } getMedians(a); ini.close(); }
这样就能正确读取用户输入的数组并计算中位数。
内容的提问来源于stack exchange,提问作者Jonatino
相关产品推荐
相关产品推荐

