Получить индексы 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. Бытие int
s их значения, вероятно, придется упаковать, чтобы добавить в коллекцию (если вы не свернули свой собственный), что значительно увеличивает накладные расходы.
немного поздно в ответе, вы также можете использовать эту функцию, которую я написал:
/**
* 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
. Дайте ему запустить и посмотреть, если он работает для вас