Как печатать индексы 10 наименьших значений в массиве

Мне нужно выбрать 10 наименьших чисел из массива (с 2000 элементами) и вывести их индексы.

Сначала я попытался просто отсортировать этот массив и вывести массив значений [от 0 до 9]. Это были самые маленькие числа, но я потерял индексы этих значений, которые были в несортированном массиве.

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

Пример использования кода с treeMap:

  TreeMap<Integer, String> treemap = new TreeMap<Integer, String>();

  treemap.put(2, "two");
  treemap.put(1, "one");
  treemap.put(3, "three");
  treemap.put(6, "six");
  treemap.put(6, "six2");
  treemap.put(5, "five");      

  Collection<String> coll=treemap.values();
  System.out.println("Value of the collection: "+coll);  

До сих пор я не использую treeMap, поэтому возможно, что существует какой-то простой способ исправить это. Или лучше использовать что-то другое?

буду благодарен за любую помощь


person Petr Šrámek    schedule 02.11.2013    source источник
comment
Вопрос печатает 10 индексов с наименьшими значениями (возможно, некоторые индексы с одинаковым значением не напечатаны) или печатает индексы с 10 наименьшими значениями (возможно, более 10, даже весь массив, если он имеет только 10 или меньше разных значений)?   -  person hyde    schedule 02.11.2013
comment
Это правда. Спасибо за лучшее название темы :)   -  person Petr Šrámek    schedule 02.11.2013


Ответы (5)


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

Например, вы хотите отсортировать:

6 2 7 4

Составление (value, index) пар:

(6, 0) (2, 1) (7, 2) (4, 3) 

Сортировка по value:

(2, 1) (4, 3) (6, 0) (7, 2) 

Индексы:

1 3 0 2

Ваш подход к TreeMap в порядке. Единственная модификация, которую вам нужно сделать, выглядит так:

class Pair implements Comparable<Pair> {
    int value;
    int index;

    @Override
    int compareTo(Pair other) { return value - other.value };
}

Map<Pair, String> map = new TreeMap<Pair, String>();
person Adam Stelmaszczyk    schedule 02.11.2013

Создайте простой класс для хранения двух целых чисел или используйте дженерики для любого значения:

class Item<T> { 
    public int index;
    public T value;
    public Item(int index, T value) {
        this.index = index;
        this.value = value;
    }
}

И используйте Collections.sort.

double[] original = { 1.0, 7.0, 3.0, -1.0, 5.0 };

List<Item> l = new ArrayList<Item<Double>>();
for (int i = 0; i < original.length; i++)
    l.add(new Item<Double>(i, original[i]));

Collections.sort(l, new Comparator<Item<Double>>() {
    public int compare(Item o1, Item o2) {
        return Double.compare(o1.value, o2.value);
    }
});

for (int i = 0; i < 10 && i < l.size(); i++) {
    System.out.printf("index: %f, value: %f%n", 
              l.get(i).index, l.get(i).value);
}

Выход:

index: 3, value: -1
index: 0, value: 1
index: 2, value: 3
index: 4, value: 5
index: 1, value: 7
person azz    schedule 02.11.2013
comment
Можно ли изменить его на двойные значения? Все мои попытки изменить его заканчивались какой-то ошибкой. - person Petr Šrámek; 02.11.2013
comment
@PetrŠrámek Да, смотрите изменения к ответу - person azz; 02.11.2013

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

public class Quicksort 
{
    private int[] numbers;
    private int number;

    public void sort(int[] values) {
        if (values ==null || values.length==0){
           return;
        }
        this.numbers = values;
        number = values.length;
        quicksort(0, number - 1);
    }

    private void quicksort(int low, int high) {
        int i = low, j = high;
        int pivot = numbers[low + (high-low)/2];

        while (i <= j) {
            while (numbers[i] < pivot) {
                i++;
            }
            while (numbers[j] > pivot) {
               j--;
            }

            if (i <= j) {
                exchange(i, j);
                i++;
                j--;
            }
        }

        if (low < j)
            quicksort(low, j);
        if (i < high)
            quicksort(i, high);
    }

Здесь мы вносим изменения

    private void exchange(int i, int j) {
    int temp = numbers[i];
    numbers[i] = numbers[j];
    numbers[j] = temp;

    // NOTICE THIS exchange the indexes as well
    temp = index_numbers[i];
    index_numbers[i] = index_numbers[j];
    index_numbers[j] = temp;
    }
}
person Ankit Rustagi    schedule 02.11.2013
comment
Читать будет легко с некоторыми примечаниями, поясняющими логику - person iShaalan; 02.11.2013

короткое решение:

  1. Создайте массив индексов (простой цикл for для инициализации).

  2. Отсортируйте этот массив индексов с помощью пользовательской функции сравнения, которая сравнивает значения индекса в другом массиве. Примечание: используйте стабильную сортировку, если вы хотите печатать индексы по порядку.

  3. Повторить массив отсортированных индексов, распечатать индексы и подсчитать различные значения (увеличить счетчик при изменении значения), остановить, когда счетчик станет равным 11.

person hyde    schedule 02.11.2013

person    schedule
comment
Можно ли изменить его на двойные значения? Все мои попытки изменить его заканчивались какой-то ошибкой. - person Petr Šrámek; 02.11.2013
comment
@PetrŠrámek Да, конечно, просто измените поле значения как примитив double и используйте статический метод compare в классе Double, т.е. int compareValue = Double.compare(value, m.value); в методе compareTo. - person Alexis C.; 02.11.2013
comment
Спасибо... Я попробовал это до того, как добавил этот комментарий, но, вероятно, где-то ошибся, потому что теперь это работает хорошо. - person Petr Šrámek; 02.11.2013
comment
@PetrŠrámek Пожалуйста. Круто, теперь работает =) - person Alexis C.; 02.11.2013