如何计算数组的中位数?

我正在尝试计算由文本字段接收的输入填充的数组的总数,平均值和中位数。 我已经设法计算出总数和均值,我只是无法得到中位数。 我认为在我能做到这一点之前需要对数组进行排序,但我不知道如何做到这一点。 这是问题,还是有另一个我没找到的? 这是我的代码:

import java.applet.Applet; import java.awt.Graphics; import java.awt.*; import java.awt.event.*; public class whileloopq extends Applet implements ActionListener { Label label; TextField input; int num; int index; int[] numArray = new int[20]; int sum; int total; double avg; int median; public void init () { label = new Label("Enter numbers"); input = new TextField(5); add(label); add(input); input.addActionListener(this); index = 0; } public void actionPerformed (ActionEvent ev) { int num = Integer.parseInt(input.getText()); numArray[index] = num; index++; if (index == 20) input.setEnabled(false); input.setText(""); sum = 0; for (int i = 0; i < numArray.length; i++) { sum += numArray[i]; } total = sum; avg = total / index; median = numArray[numArray.length/2]; repaint(); } public void paint (Graphics graf) { graf.drawString("Total = " + Integer.toString(total), 25, 85); graf.drawString("Average = " + Double.toString(avg), 25, 100); graf.drawString("Median = " + Integer.toString(median), 25, 115); } } 

Java中的Arrays类有一个静态排序函数,您可以使用Arrays.sort(numArray)调用它。

 Arrays.sort(numArray); double median; if (numArray.length % 2 == 0) median = ((double)numArray[numArray.length/2] + (double)numArray[numArray.length/2 - 1])/2; else median = (double) numArray[numArray.length/2]; 

对arrays进行排序是不必要且低效的。 有一种QuickSort ( QuickSelect )算法的变体,其平均运行时间为O(n); 如果你先排序,那么你就是O(n log n)。 它实际上找到了列表中的第n个最小项; 对于中位数,您只需使用n =列表长度的一半。 我们称之为quickNth(list,n)。

概念是找到第n个最小值,选择一个“枢轴”值。 (具体如何选择它并不重要;如果您知道数据将是完全随机的,您可以获取列表中的第一项。)

将原始列表拆分为三个较小的列表:

  • 一个值小于枢轴的值。
  • 一个值等于枢轴的值。
  • 一个值大于枢轴的值。

然后你有三种情况:

  1. “较小”列表具有> = n项。 在这种情况下,您知道第n个最小值在该列表中。 返回quickNth(更小,n)。
  2. 较小的列表具有 = n项。 在这种情况下,第n个等于“相等”列表中的任何项目; 你完成了。
  3. n大于较小和相等列表的长度之和。 在这种情况下,您基本上可以跳过这两个,并相应地调整n。 返回quickNth(更大,n – 长度(更小) – 长度(相等))。

完成。

如果您不确定数据是否完全随机,则需要更加精确地选择枢轴。 取列表中第一个值的中位数,列表中的最后一个值,以及两个中间值之间的值非常好。

如果您选择枢轴非常不走运,并且总是选择最小或最高值作为枢轴,则需要O(n ^ 2)时间; 那很糟。 但是,如果您选择具有合适算法的枢轴,也不太可能。

示例QuickSelect代码

如果你想在这里使用任何外部库,那么Apache commons数学库可以用来计算中位数 。
有关更多方法和用法,请参阅API文档

 import org.apache.commons.math3.*; ..... ...... ........ //calculate median public double getMedian(double[] values){ Median median = new Median(); double medianValue = median.evaluate(values); return medianValue; } ....... 
  • 有关评估方法AbstractUnivariateStatistic#evaluate的更多信息

更新

在程序中计算

通常,使用此处给出的以下两个公式计算中值

如果n是奇数,那么中位数(M)=((n + 1)/ 2)项项的值。
如果n是偶数,则中位数(M)= [((n)/ 2)项项的值+((n)/ 2 + 1)项项目] / 2

在你的程序中你有numArray ,首先你需要使用Arrays numArray来排序数组

 Arrays.sort(numArray); int middle = numArray.length/2; int medianValue = 0; //declare variable if (numArray.length%2 == 1) medianValue = numArray[middle]; else medianValue = (numArray[middle-1] + numArray[middle]) / 2; 
 Arrays.sort(numArray); int middle = ((numArray.length) / 2); if(numArray.length % 2 == 0){ int medianA = numArray[middle]; int medianB = numArray[middle-1]; median = (medianA + medianB) / 2; } else{ median = numArray[middle + 1]; } 

编辑:我最初在均匀长度数组medianB设置为middle+1 ,这是错误的,因为数组开始计数为0.我已更新它使用middle-1 ,这是正确的,应该适用于具有偶数的数组长度。

尝试先排序数组。 然后在它排序之后,如果数组具有偶数量的元素,则中间两个的平均值是中值,如果它具有奇数,则中间元素是中值。

使用Arrays.sort然后取中间元素(如果数组中元素的数量n是奇数)或取两个中间元素的平均值(如果n是偶数)。

  public static long median(long[] l) { Arrays.sort(l); int middle = l.length / 2; if (l.length % 2 == 0) { long left = l[middle - 1]; long right = l[middle]; return (left + right) / 2; } else { return l[middle]; } } 

这里有些例子:

  @Test public void evenTest() { long[] l = { 5, 6, 1, 3, 2 }; Assert.assertEquals((3 + 4) / 2, median(l)); } @Test public oddTest() { long[] l = { 5, 1, 3, 2, 4 }; Assert.assertEquals(3, median(l)); } 

如果您的输入是Collection ,您可以使用Google Guava执行以下操作:

 public static long median(Collection numbers) { return median(Longs.toArray(numbers)); // requires import com.google.common.primitives.Longs; } 

我昨天遇到了类似的问题。 我用Javagenerics编写了一个方法来计算每个数字集合的中值; 你可以将我的方法应用于Doubles,Integers,Floats的集合并返回一个double。 请考虑我的方法创建另一个集合,以便不改变原始集合。 我也提供测试,玩得开心。 😉

 public static > double median(Collection numbers){ if(numbers.isEmpty()){ throw new IllegalArgumentException("Cannot compute median on empty collection of numbers"); } List numbersList = new ArrayList<>(numbers); Collections.sort(numbersList); int middle = numbersList.size()/2; if(numbersList.size() % 2 == 0){ return 0.5 * (numbersList.get(middle).doubleValue() + numbersList.get(middle-1).doubleValue()); } else { return numbersList.get(middle).doubleValue(); } } 

JUnit测试代码片段:

 /** * Test of median method, of class Utils. */ @Test public void testMedian() { System.out.println("median"); Double expResult = 3.0; Double result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,13.0)); assertEquals(expResult, result); expResult = 3.5; result = Utils.median(Arrays.asList(3.0,2.0,1.0,9.0,4.0,13.0)); assertEquals(expResult, result); } 

用法示例(考虑类名为Utils):

 List intValues = ... //omitted init Set floatValues = ... //omitted init ..... double intListMedian = Utils.median(intValues); double floatSetMedian = Utils.median(floatValues); 

注意:我的方法适用于集合,您可以将数字数组转换为此处指向的数字列表

我在看同样的统计问题。 你认为它的方法是好的,它会工作。 (已经给出了排序的答案)

但是如果你对算法性能感兴趣,我认为有几种算法比仅仅对数组进行排序有更好的性能,其中一个( QuickSelect )由@ bruce-feist的答案表示并且得到了很好的解释。

[Java实现: https : //discuss.leetcode.com/topic/14611/java-quick-select ]

但是这个算法的变体名为medians的中位数 ,你可以在这个链接上找到一个很好的解释: http : //austinrochford.com/posts/2013-10-28-median-of-medians.html

Java的实现: – https://stackoverflow.com/a/27719796/957979

您可以在https://www.youtube.com/watch?time_continue=23&v=VmogG01IjYc找到很好的解释。

它使用2堆的想法即一个最大堆和平均堆。

 class Heap { private Queue low = new PriorityQueue<>(Comparator.reverseOrder()); private Queue high = new PriorityQueue<>(); public void add(int number) { Queue target = low.size() <= high.size() ? low : high; target.add(number); balance(); } private void balance() { while(!low.isEmpty() && !high.isEmpty() && low.peek() > high.peek()) { Integer lowHead= low.poll(); Integer highHead = high.poll(); low.add(highHead); high.add(lowHead); } } public double median() { if(low.isEmpty() && high.isEmpty()) { throw new IllegalStateException("Heap is empty"); } else { return low.size() == high.size() ? (low.peek() + high.peek()) / 2.0 : low.peek(); } } 

}

查看Arrays.sort方法:

http://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html

你也应该抽象地将中位数发现到它自己的方法中,然后将值返回给调用方法。 这将使您的代码测试变得更加容易。

@Aniket有最正确的答案,但我会更改一行。

median = numArray[middle-1] + Math.abs(numArray[middle-1] - numArray[middle] )/2;

对于两个中间加起来超过int max的情况

 public int[] data={31, 29, 47, 48, 23, 30, 21 , 40, 23, 39, 47, 47, 42, 44, 23, 26, 44, 32, 20, 40}; public double median() { Arrays.sort(this.data); double result=0; int size=this.data.length; if(size%2==1) { result=data[((size-1)/2)+1]; System.out.println(" uneven size : "+result); } else { int middle_pair_first_index =(size-1)/2; result=(data[middle_pair_first_index+1]+data[middle_pair_first_index])/2; System.out.println(" Even size : "+result); } return result; } 
 Arrays.sort(numArray); return (numArray[size/2] + numArray[(size-1)/2]) / 2;