Получить индексы N максимумов в массиве java

у меня есть массив размером 1000. Как найти индексы (индексы) пяти максимальных элементов?

пример с кодом установки и моя попытка отображаются ниже:

Random rand = new Random();
int[] myArray = new int[1000];
int[] maxIndices = new int[5];
int[] maxValues = new int[5];

for (int i = 0; i < myArray.length; i++) {
  myArray[i] = rand.nextInt();
}

for (int i = 0; i < 5; i++) {
  maxIndices[i] = i;
  maxValues[i] = myArray[i];
}

for (int i = 0; i < maxIndices.length; i++) {
  for (int j = 0; j < myArray.length; j++) {
    if (myArray[j] > maxValues[i]) {
      maxIndices[i] = j;
      maxValues[i] = myArray[j];
    }
  }
}

for (int i = 0; i < maxIndices.length; i++) {
  System.out.println("Index: " + maxIndices[i]);
}

Я знаю, что проблема в том, что он постоянно присваивает наибольшее максимальное значение всем максимальным элементам. Я не уверен, как это исправить, потому что я должен сохранить значения и индексы myArray.

Я не думаю, что сортировка-это вариант, потому что мне нужно сохранить индексы. На самом деле именно эти показатели мне и нужны.

6 ответов


сортировка является опцией, за счет дополнительной памяти. Рассмотрим следующий алгоритм.

1. Allocate additional array and copy into - O(n)
2. Sort additional array - O(n lg n)
3. Lop off the top k elements (in this case 5) - O(n), since k could be up to n
4. Iterate over the original array - O(n)
    4.a search the top k elements for to see if they contain the current element - O(lg n)

таким образом, Шаг 4 (n * lg n), как и сортировка. Весь алгоритм N lg n, и очень прост в коде.

вот быстрый и грязный пример. В нем могут быть ошибки, и, очевидно, нулевая проверка и тому подобное вступают в игру.

импорт java.утиль.Массивы;

class ArrayTest {

    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9, 2, 4, 6, 8, 10};
        int[] indexes = indexesOfTopElements(arr,3);
        for(int i = 0; i < indexes.length; i++) {
            int index = indexes[i];
            System.out.println(index + " " + arr[index]);
        }
    }

    static int[] indexesOfTopElements(int[] orig, int nummax) {
        int[] copy = Arrays.copyOf(orig,orig.length);
        Arrays.sort(copy);
        int[] honey = Arrays.copyOfRange(copy,copy.length - nummax, copy.length);
        int[] result = new int[nummax];
        int resultPos = 0;
        for(int i = 0; i < orig.length; i++) {
            int onTrial = orig[i];
            int index = Arrays.binarySearch(honey,onTrial);
            if(index < 0) continue;
            result[resultPos++] = i;
        }
        return result;
    }

}

есть и другие вещи, которые вы можете сделать, чтобы уменьшить накладные расходы эта операция. Например, вместо сортировки вы можете использовать очередь, которая просто отслеживает самые большие 5. Бытие ints их значения, вероятно, придется упаковать, чтобы добавить в коллекцию (если вы не свернули свой собственный), что значительно увеличивает накладные расходы.


немного поздно в ответе, вы также можете использовать эту функцию, которую я написал:

/**
  * Return the indexes correspond to the top-k largest in an array.
  */
public static int[] maxKIndex(double[] array, int top_k) {
    double[] max = new double[top_k];
    int[] maxIndex = new int[top_k];
    Arrays.fill(max, Double.NEGATIVE_INFINITY);
    Arrays.fill(maxIndex, -1);

    top: for(int i = 0; i < array.length; i++) {
        for(int j = 0; j < top_k; j++) {
            if(array[i] > max[j]) {
                for(int x = top_k - 1; x > j; x--) {
                    maxIndex[x] = maxIndex[x-1]; max[x] = max[x-1];
                }
                maxIndex[j] = i; max[j] = array[i];
                continue top;
            }
        }
    }
    return maxIndex;
}

Извините, что отвечаю на этот старый вопрос, но мне не хватает реализации, которая имеет все следующие свойства:

  • легко читать
  • производительность
  • обработка нескольких одинаковых значений

поэтому я реализовал это:

    private int[] getBestKIndices(float[] array, int num) {
        //create sort able array with index and value pair
        IndexValuePair[] pairs = new IndexValuePair[array.length];
        for (int i = 0; i < array.length; i++) {
            pairs[i] = new IndexValuePair(i, array[i]);
        }

        //sort
        Arrays.sort(pairs, new Comparator<IndexValuePair>() {
            public int compare(IndexValuePair o1, IndexValuePair o2) {
                return Float.compare(o2.value, o1.value);
            }
        });

        //extract the indices
        int[] result = new int[num];
        for (int i = 0; i < num; i++) {
            result[i] = pairs[i].index;
        }
        return result;
    }

    private class IndexValuePair {
        private int index;
        private float value;

        public IndexValuePair(int index, float value) {
            this.index = index;
            this.value = value;
        }
    }

моя быстрая и немного "думать вне коробки" идея заключалась бы в использовании EvictingQueue который содержит максимум 5 элементов. Вам пришлось предварительно заполнить его первыми пятью элементами из вашего массива (сделайте это в порядке возрастания, поэтому первый элемент, который вы добавляете, является самым низким из пяти).

чем вам нужно перебирать массив и добавлять новый элемент в очередь, когда текущее значение больше самого низкого значения в очереди. Запомнить индексы, создайте объект-оболочку (пару значение / индекс).

после итерации по всему массиву у вас есть пять пар максимальное значение/индекс в очереди (в порядке убывания).

это решение O(n).


массивы.сортировка (myArray), затем возьмите последние 5 элементов.

сортировка копию, если вы хотите сохранить исходный порядок.

Если вы хотите индексы, нет быстрого и грязного решения, как это было бы в python или некоторых других языках. Вы сортируете и сканируете, но это уродливо.

или вы можете пойти objecty-это java, в конце концов. Создайте объект ArrayMaxFilter. Он будет иметь частный класс ArrayElement, который состоит из индекса и значения и имеет естественный порядок по стоимости. Он будет иметь метод, который принимает пару ints, index и value, создает ArrayElement из них и помещает их в очередь приоритетов длиной 5. (или сколько вы хотите найти). Отправьте каждую пару индекс / значение из массива, затем сообщите значения, оставшиеся в очереди. (да, приоритетная очередь традиционно сохраняет самые низкие значения, но вы можете перевернуть это в своей реализации)


вот мое решение. Создайте класс, который связывает Индис со значением:

public class IndiceValuePair{
    private int indice;
    private int value;

    public IndiceValuePair(int ind, int val){
        indice = ind;
        value = val;
    }
    public int getIndice(){
        return indice;
    }
    public int getValue(){
        return value;
    }
}

а затем используйте этот класс в своем основном методе:

public static void main(String[] args){
    Random rand = new Random();
    int[] myArray = new int[10];
    IndiceValuePair[] pairs = new IndiceValuePair[5];
    System.out.println("Here are the indices and their values:");
    for(int i = 0; i < myArray.length; i++) {
        myArray[i] = rand.nextInt(100);
        System.out.println(i+ ": " + myArray[i]);
        for(int j = 0; j < pairs.length; j++){
            //for the first five entries
            if(pairs[j] == null){
                pairs[j] = new IndiceValuePair(i, myArray[i]);
                break;
            }
            else if(pairs[j].getValue() < myArray[i]){
                //inserts the new pair into its correct spot
                for(int k = 4; k > j; k--){
                    pairs[k] = pairs [k-1];
                }
                pairs[j] = new IndiceValuePair(i, myArray[i]);
                break;
            }
        }
    }
    System.out.println("\n5 Max indices and their values");
    for(int i = 0; i < pairs.length; i++){
        System.out.println(pairs[i].getIndice() + ": " + pairs[i].getValue());
    }
}

и пример вывода из выполнения:

Here are the indices and their values:
0: 13
1: 71
2: 45
3: 38
4: 43
5: 9
6: 4
7: 5
8: 59
9: 60

5 Max indices and their values
1: 71
9: 60
8: 59
2: 45
4: 43

пример, который я привел, генерирует только десять ints со значением от 0 до 99, чтобы я мог видеть, что он работает. Вы можете легко изменить это, чтобы соответствовать 1000 значений любого размера. Кроме того, вместо запуска 3 отдельных циклов for я проверил, не является ли новейшее значение I add-это максимальное значение сразу после добавления в myArray. Дайте ему запустить и посмотреть, если он работает для вас