Снижение временной сложности создания массива рангов

публичный рейтинг (String [] имена, float [] баллы) { nameTest = new Cities [names.length]; rankTest = новые города[имена.длина]; город = новые города[имена.длина]; scoreRanks = новый Float[scores.length]; for (int i = 0; i ‹ scores.length - 1; i++) { if (scores[i] == scores[i + 1]) throw new IllegalArgumentException(); } if (names == null || scores == null) throw new NullPointerException(); if (names.length != scores.length) выдать новое исключение IllegalArgumentException();

        for (int p = 0; p < scoreRanks.length; p++) {
            scoreRanks[p] = scores[p];
        }
        int[] ranking = new int[names.length];
        for (int k = 0; k < ranking.length; k++) {
            ranking[this.smallestIndex()] = k + 1;
        }
        for (int i = 0; i < ranking.length; i++) {
            city[i] = new Cities(names[i], ranking[i]);
            nameTest[i] = new Cities(names[i], ranking[i]);
            rankTest[i] = new Cities(names[i], ranking[i]);
        }
        Arrays.sort(nameTest, Cities.BY_NAME);
        Arrays.sort(rankTest, Cities.BY_RANK);
        for (int i = 0; i < names.length - 1; i++) {
            if (nameTest[i].getName().equals(nameTest[i + 1].getName())
                    || nameTest[i].getName() == null
                    || rankTest[i].getRank() == rankTest[i + 1].getRank())
                throw new IllegalArgumentException();
        }
    }

    public int smallestIndex() {
        float smallest = 0.0f;
        int i;
        for (i = 0; i < scoreRanks.length; i++) {
            if (scoreRanks[i] > 0.0f) {
                smallest = scoreRanks[i];
                break;
            } else
                continue;
        }
        int j = 1;
        while (j < scoreRanks.length) {
            if (scoreRanks[j] < smallest && scoreRanks[j] != 0.0f) {
                smallest = scoreRanks[j];
                i = j;
            }
            j++;
        }
        scoreRanks[i] = 0.0f;
        return i;
    }

Это мой конструктор рейтинга. В настоящее время вызов наименьшего индекса () внутри цикла for увеличивает его до времени O (n ^ 2), но мне нужно, чтобы он выполнялся не более чем за время O (n log n).

Что это делает, так это принимает массив результатов и имен. Тогда место с САМЫМ НИЗКИМ счетом будет рангом 1, следующим самым низким будет ранг 2, и так далее, и так далее. Затем я могу создать объекты Cities, где имена[i] соответствуют рейтингу[i].

Надеюсь, это имеет смысл. Купите да, я не понимаю, что я могу сделать, чтобы получить тот же результат, но за время O (n log n). Мой код работает отлично, я думаю, он слишком медленный :(.

Кроме того, будет ли O(2n log n + 5n) сводиться к O(n log n)?


person Tyler Dahle    schedule 27.02.2014    source источник
comment
1. Что такое оригинальный выпуск? 2. Да, O(2n log + 5n) = O(n logn)   -  person Alma Do    schedule 27.02.2014


Ответы (1)


Судя по вашему описанию, в основном вы хотите отсортировать список по возрастанию счета. Изучая свой код в smallestIndex, кажется, что вы действительно делаете это очень неэффективным способом. Если мы хотим сохранить этот метод, я предлагаю изменить scoreRanks[i] = 0.0f на scoreRanks[i] = Float.MAX_VALUE и упростить метод, просто зациклившись один раз.

Но для эффективного выполнения вашей задачи я предлагаю полностью удалить smallestIndex. Я вижу, что вы уже используете Arrays.sort с пользовательскими компараторами. Вы можете эффективно решить свою задачу, просто используя тот же метод. Вы можете создать собственный компаратор, как описано в этом вопросе: Получить индексы массив после сортировки?

class ArrayIndexComparator implements Comparator<Integer>
{
    private Float[] scores;

    public ArrayIndexComparator(float[] scores)
    {
        this.scores = new Float[scores.length];
        for(int i=0; i<scores.length; i++){
            this.scores[i] = scores[i];
        }
    }

    public Integer[] createIndexArray()
    {
        Integer[] indexes = new Integer[scores.length];
        for (int i = 0; i < scores.length; i++)
        {
            indexes[i] = i;
        }
        return indexes;
    }

    @Override
    public int compare(Integer index1, Integer index2)
    {
        // Autounbox from Integer to int to use as array indexes
        return scores[index1].compareTo(scores[index2]);
    }

    public static void main(String[] args){
        float[] scoreRanks = new float[]{2.0f,3.0f,1.0f};
        ArrayIndexComparator comparator = new ArrayIndexComparator(scoreRanks);
        Integer[] indexes = comparator.createIndexArray();
        Arrays.sort(indexes, comparator);
        int[] ranking = new int[indexes.length];
        for (int i = 0; i < ranking.length; i++) {
            ranking[indexes[i]] = i + 1;
        }
        for (int i = 0; i < ranking.length; i++){
            System.out.println(ranking[i]+" "+scoreRanks[i]);
        }
        // Will print:
        // 2.0 2
        // 3.0 3
        // 1.0 1
    }
}

public Ranking(String[] names, float[] scores) {
    nameTest = new Cities[names.length];
    rankTest = new Cities[names.length];
    city = new Cities[names.length];
    scoreRanks = new Float[scores.length];
    for (int i = 0; i < scores.length - 1; i++) {
        if (scores[i] == scores[i + 1])
            throw new IllegalArgumentException();
    }
    if (names == null || scores == null)
        throw new NullPointerException();
    if (names.length != scores.length)
        throw new IllegalArgumentException();
    for (int p = 0; p < scoreRanks.length; p++) {
        scoreRanks[p] = scores[p];
    }
    // This is the updated part
    ArrayIndexComparator comparator = new ArrayIndexComparator(scoreRanks);
    Integer[] indexes = comparator.createIndexArray();
    Arrays.sort(indexes, comparator);
    int[] ranking = new int[indexes.length];
    for (int i = 0; i < ranking.length; i++) {
        ranking[indexes[i]] = i + 1;
    }
    // Up until this part
    for (int i = 0; i < ranking.length; i++) {
        city[i] = new Cities(names[i], ranking[i]);
        nameTest[i] = new Cities(names[i], ranking[i]);
        rankTest[i] = new Cities(names[i], ranking[i]);
    }
    Arrays.sort(nameTest, Cities.BY_NAME);
    Arrays.sort(rankTest, Cities.BY_RANK);
    for (int i = 0; i < names.length - 1; i++) {
        if (nameTest[i].getName().equals(nameTest[i + 1].getName())
                || nameTest[i].getName() == null
                || rankTest[i].getRank() == rankTest[i + 1].getRank())
            throw new IllegalArgumentException();
    }
}

Таким образом, вы будете использовать метод сортировки в классе Arrays, который равен O(n log n).

person justhalf    schedule 27.02.2014
comment
Хм... но разве это не сортировка массива rating[] в [1, 2, 3, 4,...]? Потому что проблема в том, что я не могу этого сделать. Массив scores[] не может быть отсортирован, равно как иRanking[]. Объекты города могут быть позже, но массивы должны сопоставляться с их соответствующей строкой и, следовательно, не могут быть отсортированы. - person Tyler Dahle; 28.02.2014
comment
Нет, это даст тот же массив ranking, что и ваш метод. Arrays.sort будет сортировать индекс оценок на основе оценок. Таким образом, в моем тестовом примере выше (я добавил тестовый пример) массив indexes будет {2, 0, 1}, имея в виду, что scores[2] — самый маленький, scores[0] — второй по величине, а scores[1] — самый большой. Тогда это по сути то же самое, что и ваш метод smallestIndex, только результат уже находится в массиве, а не вызывается метод n раз. Вы можете проверить результат ranking, чтобы убедиться, что он правильный. - person justhalf; 28.02.2014
comment
Ermahgerd это как черная магия! Большое тебе спасибо! Он работает как сон и просто снизил мою сложность с O(n^2) до O(n log n)! - person Tyler Dahle; 28.02.2014
comment
Рад, что помог =). Сразу хочу сказать, что это не сон, а реальность. И на самом деле это помогло бы мне и другим, если бы вы могли принять этот ответ, чтобы люди, ищущие сортировку по рангу, могли найти этот вопрос с ответом = D (также проголосуйте, если вам это нравится) - person justhalf; 28.02.2014