如何计算数组的中位数?

时间:2012-08-14 15:28:23

标签: java arrays

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

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);



    }
}

15 个答案:

答案 0 :(得分:56)

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];

答案 1 :(得分:30)

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

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

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

  • 值小于数据透视的值。
  • 一个值与枢轴相等的值。
  • 一个值大于枢轴的值。

然后您有三种情况:

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

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

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

    Sample QuickSelect code

答案 2 :(得分:6)

如果您想在Apache commons math library使用任何外部库,可以使用Median来计算API documentation。 有关更多方法和用法,请查看AbstractUnivariateStatistic#evaluate

import org.apache.commons.math3.*;
.....
......
........
//calculate median
public double getMedian(double[] values){
 Median median = new Median();
 double medianValue = median.evaluate(values);
 return medianValue;
}
.......

更新

在程序中计算

通常,使用以下两个公式Arrays#sort

计算中位数
  

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

在您的程序中,您有numArray,首先需要使用{{3}}对数组进行排序

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;

答案 3 :(得分:4)

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,这是正确并且应该适用于长度均匀的数组。

答案 4 :(得分:2)

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

答案 5 :(得分: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<Long> numbers)
{
  return median(Longs.toArray(numbers)); // requires import com.google.common.primitives.Longs;
}

答案 6 :(得分:1)

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

public static <T extends Number & Comparable<T>> double median(Collection<T> numbers){
    if(numbers.isEmpty()){
        throw new IllegalArgumentException("Cannot compute median on empty collection of numbers");
    }
    List<T> 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<Integer> intValues = ... //omitted init
Set<Float> floatValues = ... //omitted init
.....
double intListMedian = Utils.median(intValues);
double floatSetMedian = Utils.median(floatValues);

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

答案 7 :(得分:1)

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

但是如果您对算法性能感兴趣,我认为有一些算法比仅仅对数组进行排序有更好的性能,其中一个(QuickSelect)由@bruce-feist的回答表示,非常很好地解释了。

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

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

这个的Java实现:   - https://stackoverflow.com/a/27719796/957979

答案 8 :(得分:1)

您可以在https://www.youtube.com/watch?time_continue=23&v=VmogG01IjYc

找到合适的解释

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

class Heap {
private Queue<Integer> low = new PriorityQueue<>(Comparator.reverseOrder());
private Queue<Integer> high = new PriorityQueue<>();

public void add(int number) {
    Queue<Integer> 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();
    }
}

}

答案 9 :(得分:0)

查看Arrays.sort方法:

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

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

答案 10 :(得分:0)

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;
    }

答案 11 :(得分:0)

Arrays.sort(numArray);
return (numArray[size/2] + numArray[(size-1)/2]) / 2;

答案 12 :(得分:0)

当list仅包含一个元素(list.size == 1)时,没有人注意。您的所有答案都将因索引超出范围的异常而崩溃,因为整数除法返回零(1/2 = 0)。正确答案(在Kotlin中):

MEDIAN("MEDIAN") {

        override fun calculate(values: List<BigDecimal>): BigDecimal? {
            if (values.size == 1) {
                return values.first()
            }
            if (values.size > 1) {
                val valuesSorted = values.sorted()
                val mid = valuesSorted.size / 2
                return if (valuesSorted.size % 2 != 0) {
                    valuesSorted[mid]
                } else {
                    AVERAGE.calculate(listOf(valuesSorted[mid - 1], valuesSorted[mid]))
                }
            }
            return null
        }
    },

答案 13 :(得分:0)

正如@ Bruce-Feist提到的那样,对于许多元素,如果您担心性能,我会避免使用任何涉及排序的解决方案。与其他答案中建议的方法不同的是Hoare算法,该算法可找到n个元素的第k个最小元素。该算法在O(n)中运行。

public int findKthSmallest(int[] array, int k)
{
    if (array.length < 10)
    {
        Arrays.sort(array);
        return array[k];
    }
    int start = 0;
    int end = array.length - 1;
    int x, temp;
    int i, j;
    while (start < end)
    {
        x = array[k];
        i = start;
        j = end;
        do
        {
            while (array[i] < x)
                i++;
            while (x < array[j])
                j--;
            if (i <= j)
            {
                temp = array[i];
                array[i] = array[j];
                array[j] = temp;
                i++;
                j--;
            }
        } while (i <= j);
        if (j < k)
            start = i;
        if (k < i)
            end = j;
    }
    return array[k];
}

并找到中位数:

public int median(int[] array)
{
    int length = array.length;
    if ((length & 1) == 0) // even
        return (findKthSmallest(array, array.length / 2) + findKthSmallest(array, array.length / 2 + 1)) / 2;
    else // odd
        return findKthSmallest(array, array.length / 2);
}

答案 14 :(得分:0)

public static int median(int[] arr) {
int median = 0;
java.util.Arrays.sort(arr);
        
for (int i=0;i<arr.length;i++) {
            
    if (arr.length % 2 == 1) {
        median = Math.round(arr[arr.length/2]);
    } else {
        median = (arr[(arr.length/2)] + arr[(arr.length/2)-1])/2;
    }
}
return median;

}