самый быстрый способ сортировки списка в Java

У меня есть следующий код на Java:

   public  class ServerInfo {
    int serverId;
    int serverDataRate;
    public ServerInfo(int serverId, int serverDataRate) {
        this.serverId = serverId;
        this.serverDataRate = serverDataRate;
    }
    public int getServerId() {
        return serverId;
    }
    public double getServerDataRate() {
        return serverDataRate;
    }
       public String toString(){
            return serverId + ":" + serverDataRate;
        }
    }    

    public class ServerInfoComparator implements Comparator<ServerInfo> {

    @Override
    public int compare(ServerInfo o1, ServerInfo o2) {
          double datarate1=o1.getServerDataRate();
          double datarate2=o2.getServerDataRate();

          if(datarate1>datarate2)
              return -1;
          else if(datarate1<datarate2)
              return +1;
          else
              return 0;
    }           
}

   public class Sample {
    List<ServerInfo> listOfServers= new ArrayList<ServerInfo>();

    public void insertIntoList(){

        listOfServers.add( new ServerInfo(0,256));
        listOfServers.add( new ServerInfo(1,270));
        listOfServers.add( new ServerInfo(2,256));
        listOfServers.add( new ServerInfo(3,290));
        listOfServers.add( new ServerInfo(4,300));
        listOfServers.add( new ServerInfo(5,300));
        listOfServers.add( new ServerInfo(6,256));
        listOfServers.add( new ServerInfo(7,265));
        listOfServers.add( new ServerInfo(8,289));
        listOfServers.add( new ServerInfo(9,310));  
    }

    public static void main( String[] args){
        Sample s = new Sample();
        s.insertIntoList();
        ServerInfoComparator com  = new ServerInfoComparator();
        Collections.sort(s.listOfServers,com);

        for( ServerInfo server: s.listOfServers){
            System.out.println(server);
        }           
    }
}

Я использую приведенный выше код для сортировки элементов в порядке убывания на основе serverDataRate. Здесь примерный набор довольно мал, если у меня есть больший примерный набор из 100 элементов в списке, и код должен был выполняться каждые 5-10 секунд. Это самый быстрый способ сортировки списка или есть более быстрый метод, о котором я не знаю?

7 ответов


Я изменил ваш тест

private final List<ServerInfo> listOfServers = new ArrayList<ServerInfo>();

public void insertIntoList() {
    for (int i = 0; i < 1000000; i++)
        listOfServers.add(new ServerInfo(i, (int) (200 + Math.random() * 200)));
}

public static void main(String[] args) {
    MyApp s = new MyApp();
    s.insertIntoList();
    ServerInfoComparator com = new ServerInfoComparator();
    long start = System.nanoTime();
    Collections.sort(s.listOfServers, com);
    long time = System.nanoTime() - start;
    System.out.printf("Sorting %,d took %.3f seconds%n", s.listOfServers.size(), time/1e9);

    for (ServerInfo server : s.listOfServers) {
//    System.out.println(server);
    }
}

и он печатает

Sorting 1,000,000 took 0.438 seconds

это совсем немного быстрее ;)

кстати: я изменил double поля int.


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

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

ранняя оптимизация-отец многих ошибок (предположения - мать).


вам не нужно использовать вызовы методов в классе, даже если поле было закрытым, что не всегда известно - private ограничивает доступ к классу, а не к объекту.

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

@Override
public int compare(ServerInfo o1, ServerInfo o2) {
/*
      double datarate1=o1.getServerDataRate ();
      double datarate2=o2.getServerDataRate ();
*/
      double datarate1=o1.serverDataRate;
      double datarate2=o2.serverDataRate;

      if (datarate1 > datarate2)
          return -1;
      else if ( datarate1 < datarate2)
          return +1;
      else
          return 0;
}           

но JVM может оптимизировать вызов функции, и в диапазоне 100 элементов он вряд ли будет измерим.

ваш метод возвращает double-можете ли вы объяснить, почему?

С помощью ints вы можете просто сделать:

@Override
public int compare (ServerInfo o1, ServerInfo o2) {
      return o2.serverDataRate - o1.serverDataRate;
}           

но рассмотрим экстремальные возможные значения для вопросов int over-and underrun.


это ненормально. Проверьте свой способ синхронизации.

long start = System.nanoTime();

// Sort here

long time = System.nanoTime() - start;
System.out.println(time / 1000000L + " Milliseconds");

учитывая, что вы не сортируете часто, скорость не должна быть проблемой. Даже с тысячами предметов, коллекций.сортировка очень быстрая.

вы пробовали свое приложение, чтобы увидеть, была ли скорость проблемой ? Преждевременная оптимизация-не очень хорошая идея:)

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


вы можете использовать структуру данных для выполнения сортировки более быстрым способом.

BST (двоичное дерево поиска) или TRIE помогут вам быстрее сортировать огромные данные.

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


во-первых,тип переменной serverDataRate-int. Но метод getter возвращает тип double. Когда компаратор работает, все getServerDataRate метод преобразует поле в формат данных londer. Если тип возврата метода getter совпадает с типом поля, то время сравнения будет короче. Во-вторых, нет необходимости использовать if(), в методе сравнения, если ваша миссия проста. Просто используйте вычитание. Вот так:


the getter:
    public int getServerDataRate() {
        return serverDataRate;
    }

in comparator:
return o1.getServerDataRate()-o2.getServerDataRate(); // from smallest to largest value
or
return o2.getServerDataRate()-o1.getServerDataRate(); // from largest to smallest value