Сортировка списка занимает много времени

1

У меня есть следующий список для сортировки:

  A 0.53
  B 0.56
  C 0.56
  D 0.98
  E 0.33

Пожалуйста, не то, чтобы мой список мог содержать 1000 таких записей. Я сортирую свой список и помещаю отсортированный список в массив как:

  String str="";
        for(String s: mylist){
            str+=s+",";
        }
        String[] sArr = str.split(",");
        String temp="";
        for(int i=0; i<sArr.length;i++) {
            for(int j= i+1; j<sArr.length;j++){
                if(sArr[i].split("\\s")[1].compareToIgnoreCase(sArr[j].split("\\s")[1])<0){
                    temp= sArr[j];
                    sArr[j]= sArr[i];
                    sArr[i]=temp;
                }
            }
        } 

       //sArr now contains the sorted list

Проблема в том, что слишком много времени для сортировки, когда у меня 1000 записей. Мой вопрос: есть ли другой выход для выполнения одной и той же задачи за меньшее время! или что-то не так с моим способом кодирования. Может кто-нибудь, пожалуйста, помогите мне.

  • 1
    Для начала вы можете использовать встроенный оптимизированный метод сортировки, например Arrays.sort ...
  • 0
    Также используйте другой алгоритм сортировки, такой как быстрая сортировка, сортировка слиянием. Также не вызывайте split("\\s") в каждом сравнении (это довольно дорогой вызов). Вместо этого создайте отдельный класс, в котором вы будете хранить свои значения.
Показать ещё 2 комментария
Теги:
arrays
performance
sorting

5 ответов

3

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

Arrays.sort(sArr);

который должен быть быстрее вашего сортировки вставки.

Если вы хотите узнать больше об алгоритмах сортировки: wikipedia

  • 1
    Обратите внимание, что для OP также необходим собственный Comparator<String> . И, вероятно, вам также следует оценить производительность алгоритма, используемого для сравнения элементов. Использование памятки в этом случае может даже ускорить это.
0

Кажется, есть две проблемы с кодом. Первое:

String str="";
for(String s: mylist) {
    str+=s+",";
}
String[] sArr = str.split(",");

Здесь вы, по-видимому, не без причины, присоединяетесь к коллекции строк, а затем снова разбиваете на массив. Это усугубляется тем фактом, что вы используете конкатенацию строк (оператор +).

В Java строки являются неизменяемыми объектами. Это означает, что каждая операция, которая выглядит так, как будто это изменение строкового объекта, фактически создает новый. Каждый раз, когда вы делаете str+=s+"," вы создаете новые объекты. Повторение этой тысячи раз очень неэффективно.

Когда вам нужно написать String как это, вы должны использовать StringBuilder. Хотя, в данном случае, я не думаю, что это необходимо вообще.

Если я правильно понял ваш код, кажется, что список mylist уже содержит ваши записи в следующем формате:

["A 0.53", "B 0.56", ...]

Если это так, вы можете отсортировать mylist напрямую.

Отсюда я буду считать, что mylist - это List<String>. Если это не так, и mylist - это действительно String[], вам просто нужно использовать Arrays.sort(mylist, comparator) вместо mylist.sort(comparator).

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

static Double doubleFromRecord(String record) {
    return Double.valueOf(record.split("\\s")[1]);
}

Таким образом, doubleFromRecord("A 0.53") возвращает 0.53 как Double.

Теперь вам просто нужно вызвать sort непосредственно в mylist передав Comparator который будет сравнивать числа из разных элементов:

mylist.sort((r1, r2) -> doubleFromRecord(r1).compareTo(doubleFromRecord(r2)));

И mylist будет отсортирован.

Компаратор:

(r1, r2) -> doubleFromRecord(r1).compareTo(doubleFromRecord(r2))

Просто берет два элемента из mylist и возвращает результат сравнения между их числовой частью.

Если вы можете, я предлагаю вам создать класс для ваших записей, например:

class Record {
    final String label;
    final double value;

    Record(String label, double value) {
        this.label = label;
        this.value = value;
    }
 }

И работайте с List<Record> вместо List<String>. Таким образом, вы можете легко сделать:

myRecordList.sort((r1, r2) -> Double.compare(r1.value, r2.value));
0

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

В настоящее время у вашего алгоритма есть время выполнения O (N ^ 2), что, как правило, довольно плохо, вот почему это O (N ^ 2)

//The outer-loop traverses through the "N" indexes of the array.
for(int i=0; i<sArr.length;i++) {

        //The inner-loop also traverses through the "N" indexes of the array
        for(int j= i+1; j<sArr.length;j++){

            //Most comparisons are able to be done in O(1)
            if(sArr[i].split("\\s")[1].compareToIgnoreCase(sArr[j].split("\\s")[1])<0){

                //Assignments are done in O(1)
                temp= sArr[j];
                sArr[j]= sArr[i];
                sArr[i]=temp;
            }
        }

Итак, мы действительно обеспокоены временем выполнения, когда N растет достаточно большим. По мере того как N растет, мы получим результат: O(N) * O(N) = O(N^2) Это потому, что мы смотрим на наихудший случай. Лучшим случаем было бы то, что все уже отсортировано, и все, что нам нужно сделать, это посмотреть на каждый элемент, что приводит к времени выполнения O(N).

Если вы посмотрите на алгоритм, такой как Quicksort (или посмотрите на Mergesort), вы обязательно увидите значительное улучшение из-за того, что в худшем случае и в лучшем случае (как правило) наблюдается время выполнения O(n log n), что значительно быстрее, чем текущий метод.

Я бы посоветовал вам взглянуть на реализацию лучших/более эффективных алгоритмов сортировки.

Я считаю, что Java реализует сортировку слияния в своей библиотеке Arrays. Arrays.sort()

0

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

import java.util.TreeSet;

public class Main {
    public static void main(String[] args) {
        TreeSet<DataPoint> set = new TreeSet<DataPoint>();
        String[] splitS;
        for (String s : YOUR_LIST) {
            splitS = s.split(" ");
            set.add(new DataPoint(splitS[0], Double.parseDouble(splitS[1])));
        }
        DataPoint[] sortedArray = new DataPoint[set.size()];
        set.toArray(sortedArray); //but to be honest there is no reason for using array at this point
    }
}

class DataPoint implements Comparable<DataPoint> {
    public String key;
    public double value;

    public DataPoint(String key, double value) {
        this.key = key;
        this.value = value;
    }

    public int compareTo(DataPoint p){
        return Double.compare(value, p.value);
    }
}
0

Ваш код опирается на множество операций со строками. Строки неизменны в java. Например: если у вас есть String a и String b, и вы пишете + = b; java не просто добавляет String b в a. Он создает новый экземпляр String из строки a + String b, в результате чего создается новый объект String. Выполнение этого один или два раза не имеет большого значения, но ваш код сильно полагается на это.

Мой подход заключался бы в создании нового класса для ваших данных, который реализует интерфейс Comarable:

public class DataPoint implements Comparable<DataPoint>{
    public String key;
    public double value;

    public int compareTo(DataPoint p2){
        if(this.value < p2.value)
             return -1;
        if(this.value == p2.value)
             return 0;
        if(this.value > p2.value)
             return 1;
    }
}

Затем создайте список этих объектов DataPoint и вызовите Collections.sort(dataPointList);

Затем DataPointList содержит упорядоченный порядок значений.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню