Подсчет вхождений целых чисел в массиве [duplicate]
этот вопрос уже есть ответ здесь:
Я пишу программу, которая подсчитывает количество повторений целых чисел, введенных в массив, например, если вы ввели 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, и проблема не в методе, который подсчитывает вхождения, потому что при вводе чисел вместо переменной значение изменяется.
есть ли способ что я могу изменить это, чтобы он правильно распечатал вхождения, или я должен попробовать что-то еще? И чем проще решение, тем лучше, поскольку я еще не прошел мимо массивов с одним измерением.
Спасибо за помощь!
5 ответов
что я должен сказать, мне потребовалось некоторое время, чтобы выяснить, что две переменные count
и countNum
represent for, возможно, некоторые комментарии необходимы. Но в конце концов я обнаруживаю жучок.
предположим, входные десять чисел:5, 6, 7, 8, 5, 6, 7, 8, 5, 6
после сортировки, numList
- это : 5, 5, 5, 6, 6, 6, 7, 7, 8, 8
массив count
возвращено occurrences()
должно быть: [1, 2, 3, 1, 2, 3, 1, 2, 1, 2]
на самом деле единственными полезными числами в этом массиве результатов являются:
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
в другие числа, как первые два числа 1, 2
до 3
, используются только для вычисления суммы вхождений постепенно, верно? Таким образом, ваша логика цикла должна быть изменена следующим образом:
-
удалить первый элемент
if
блок кода: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
условие:if ((num + 1) == MAX_NUM || numList[num] != numList[num + 1]) { ...... }
после этого, ваш код должен работать хорошо, как ожидалось.
кстати, ты действительно не нужно делать это так сложно. Просто попробуйте HashMap
:)
Попробовать Этого 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 и напечатайте возникновение чисел, как это:
HashMap<Integer, Integer> table = getRepetitions(testCases);
for (int key: table.keySet()) {
System.out.println(key + " occur " + table.get(key) + " times");
}
выход:
Я бы использовал сумку, коллекцию, которая подсчитывает количество раз, когда элемент появляется в коллекции. 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
для генерации счетчиков, но de rigueur вам даже не нужен массив. Просто добавьте элементы в 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");
}
вы можете начать с инициализации массива значений между 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см. также radix сортировать подсчет вроде.
Я думаю, вы можете значительно упростить свой код, если используете этот подход. Вам все равно нужно изменить, чтобы включить MAX_NUM
и MAX_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);
}
}