在数组中统计整数出现的次数

8
我正在编写一个程序,用于统计输入数组中整数的出现次数。例如,如果您键入了1 1 1 1 2 1 3 5 2 3,则程序将打印不同数字及其出现次数,如下所示:
1出现了5次, 2出现了2次, 3出现了2次, 5出现了1次。
除了一个问题外,程序已经接近完成,我无法解决:
import java.util.Scanner;
import java.util.Arrays;
public class CountOccurrences
{
   public static void main (String [] args)
   { 

    Scanner scan = new Scanner (System.in);

    final int MAX_NUM = 10;  

    final int MAX_VALUE = 100;

    int [] numList;

    int num;

    int numCount;

    int [] occurrences; 

    int count[];

    String end;

    numList = new int [MAX_NUM];

    occurrences = new int [MAX_NUM];

    count = new int [MAX_NUM];

 do
  {
     System.out.print ("Enter 10 integers between 1 and 100: ");

     for (num = 0; num < MAX_NUM; num++)
     {
        numList[num] = scan.nextInt();
     }

     Arrays.sort(numList);

     count = occurrences (numList); 

     System.out.println();   

     for (num = 0; num < MAX_NUM; num++)
     {
        if (num == 0)
        {
           if (count[num] <= 1)
              System.out.println (numList[num] + " occurs " + count[num] + " time");

           if (count[num] > 1)
              System.out.println (numList[num] + " occurs " + count[num] + " times");
        } 

        if (num > 0 && numList[num] != numList[num - 1])
        {
           if (count[num] <= 1)
              System.out.println (numList[num] + " occurs " + count[num] + " time");

           if (count[num] > 1)
              System.out.println (numList[num] + " occurs " + count[num] + " times");
        }   
     }          

     System.out.print ("\nContinue? <y/n> ");
     end = scan.next(); 

  } while (!end.equalsIgnoreCase("n"));
}


 public static int [] occurrences (int [] list)
 {
      final int MAX_VALUE = 100;

      int num;

      int [] countNum = new int [MAX_VALUE];

      int [] counts = new int [MAX_VALUE];

      for (num = 0; num < list.length; num++)
  {
     counts[num] = countNum[list[num]] += 1;
  }

  return counts;
 } 
}

我遇到的问题是,无论'num'的当前值是多少,'count'总是只打印出1,而且问题不在于计算出现次数的方法,因为当你在变量位置输入数字时,值就会改变。
有没有办法可以改变这种情况,使其正确地打印出现次数呢?还是我应该尝试其他方法? 而且,解决方案越简单越好,因为我还没有超过一维数组。
谢谢您的帮助!

4
请将以下内容翻译成中文:作为一个学习调试的机会,请使用IDE(如eclipse,Netbeans,IntellIJ等)提供的调试工具。请利用这个机会学习调试。所有的IDE(如eclipse,Netbeans,IntellIJ等)都配备了很棒的调试工具。 - Jayan
1
问题出在你的occurrences函数上。counts[num] = countNum[list[num]] += 1;这一行并不是你想象中的那样。它在数组中移动,将数字的计数放在单独的索引中。例如,对于你当前的输入,counts数组的值为[1, 2, 3, 4, 5, 1, 2, 1, 2, 1, ... 0]。第一个[1, 2, 3, 4, 5是因为你的数组中有5个1,接下来的1, 2是因为你的数组中有2个2,以此类推。你需要重新编写你的occurrences函数。本来可以把这个作为答案留下,但问题已经关闭了。 - Shadow
5个回答

3

尝试使用HashMap。对于这种类型的问题,哈希非常高效和快速。

我编写了这个函数,它接受一个数组并返回一个HashMap,其中键是数字,值是该数字的出现次数。

public static HashMap<Integer, Integer> getRepetitions(int[] testCases) {    
    HashMap<Integer, Integer> numberAppearance = new HashMap<Integer, Integer>();

    for(int n: testCases) {
        if(numberAppearance.containsKey(n)) {
            int counter = numberAppearance.get(n);
            counter = counter+1;
            numberAppearance.put(n, counter);
        } else {
            numberAppearance.put(n, 1);
        }
    }
    return numberAppearance;
}

现在迭代哈希映射并打印数字的出现次数,格式如下:
HashMap<Integer, Integer> table = getRepetitions(testCases);

for (int key: table.keySet()) {
        System.out.println(key + " occur " + table.get(key) + " times");
}

输出:

在此输入图片描述


(注:该内容为HTML代码,无需翻译)

2
不鼓励使用 HashTable,请改为使用 HashMap - Ghazanfar
@MohammadGhazanfar 当你说“discouraged”,你是什么意思? - smac89
@Smac89 请阅读这个。自从Java 2平台v1.2版本以来,这个类已经进行了改进... - Ghazanfar

2
我建议使用一个 Bag 集合,它可以统计集合中每个项目出现的次数。Apache Commons 提供了该实现。以下是他们的接口文档和已排序的树实现文档链接:接口已排序的树实现
实现方式如下:
Bag<Integer> bag = new TreeBag<Integer>();
for (int i = 0; i < numList.length; i++) {
    bag.add(numList[i]);
}
for (int uniqueNumber: bag.uniqueSet()) {
    System.out.println("Number " + uniqueNumber + " counted " + bag.getCount(uniqueNumber) + " times");
}

上面的示例从您的numList数组中取出元素并将其添加到Bag中以生成计数,但您甚至不需要使用数组。 只需直接将元素添加到Bag中即可。 如下所示:

// Make your bag.
Bag<Integer> bag = new TreeBag<Integer>();

...

// Populate your bag.
for (num = 0; num < MAX_NUM; num++) {
    bag.add(scan.nextInt());
}

...

// Print the counts for each unique item in your bag.
for (int uniqueNumber: bag.uniqueSet()) {
    System.out.println("Number " + uniqueNumber + " counted " + bag.getCount(uniqueNumber) + " times");
}

1
你可以通过初始化一个介于 MIN 和 MAX 之间的值数组来开始。当该值出现时,你可以向数组的每个元素添加内容1。例如,如下代码:
Scanner scan = new Scanner(System.in);
final int MAX_NUM = 10;
final int MAX_VALUE = 100;
final int MIN_VALUE = 1;
final int SIZE = MAX_VALUE - MIN_VALUE;
int[] numList = new int[SIZE];
System.out.printf("Enter %d integers between %d and %d:%n", 
        MAX_NUM, MIN_VALUE, MAX_VALUE);
for (int i = 0; i < MAX_NUM; i++) {
  System.out.printf("Please enter number %d: ", i + 1);
  System.out.flush();
  if (!scan.hasNextInt()) {
    System.out.printf("%s is not an int%n", scan.nextLine());
    i--;
    continue;
  }
  int v = scan.nextInt();
  if (v < MIN_VALUE || v > MAX_VALUE) {
    System.out.printf("%d is not between %d and %d%n", 
            v, MIN_VALUE, MAX_VALUE);
    continue;
  }
  numList[v - MIN_VALUE]++;
}
boolean first = true;
for (int i = 0; i < SIZE; i++) {
  if (numList[i] > 0) {
    if (!first) {
      System.out.print(", ");
    } else {
      first = false;
    }
    if (numList[i] > 1) {
      System.out.printf("%d occurs %d times", 
              i + MIN_VALUE, numList[i]);
    } else {
      System.out.printf("%d occurs once", i + MIN_VALUE);
    }
  }
}
System.out.println();

1请参阅 计数排序,忽略 基数排序


1
What I have to say is, it took me a while to figure out what the two variables count and countNum represent for, maybe some comments are needed. But finally I find out the bug.
Suppose input ten numbers are: 5, 6, 7, 8, 5, 6, 7, 8, 5, 6 After sort, numList is : 5, 5, 5, 6, 6, 6, 7, 7, 8, 8 The array count returned by occurrences()should be: [1, 2, 3, 1, 2, 3, 1, 2, 1, 2] Actually the only useful numbers in this result array are:
count[2]: 3     count number for numList[2]: 5
count[5]: 3     count number for numList[5]: 6
count[7]: 2     count number for numList[7]: 7
count[9]: 2     count number for numList[9]: 8

其他数字,比如在数字3之前的前两个数字1, 2,只用于递增地计算总出现次数,是吗?因此,你的循环逻辑应该改为以下内容:
  1. remove the first if code block:

    if (num == 0)
    {
       if (count[num] <= 1)
          System.out.println (numList[num] + " occurs " + count[num] + " time");
    
       if (count[num] > 1)
          System.out.println (numList[num] + " occurs " + count[num] + " times");
    } 
    
  2. Change the second if condition to:

    if ((num + 1) == MAX_NUM || numList[num] != numList[num + 1]) {
        ......
    }
    
在此之后,您的代码应该按预期正常工作。
顺便说一句,您真的不需要这么复杂地做。只需尝试使用HashMap :)

这正是我所需要的,谢谢!下次有问题时,我一定会添加注释 :) - Len

0

如果你使用这种方法,我认为你可以大大简化你的代码。你仍然需要修改以包括MAX_NUMMAX_VALUE

public static void main(String[] args) {

    Integer[] array = {1,2,0,3,4,5,6,6,7,8};
    Stack stack = new Stack();

    Arrays.sort(array, Collections.reverseOrder());

    for(int i : array){
        stack.push(i);
    }

    int currentNumber = Integer.parseInt(stack.pop().toString()) , count = 1;

    try {
        while (stack.size() >= 0) {
            if (currentNumber != Integer.parseInt(stack.peek().toString())) {
                System.out.printf("%d occurs %d times, ", currentNumber, count);
                currentNumber = Integer.parseInt(stack.pop().toString());
                count = 1;
            } else {
                currentNumber = Integer.parseInt(stack.pop().toString());
                count++;
            }
        }
    } catch (EmptyStackException e) {
         System.out.printf("%d occurs %d times.", currentNumber, count);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接