У меня есть следующий список для сортировки:
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 записей. Мой вопрос: есть ли другой выход для выполнения одной и той же задачи за меньшее время! или что-то не так с моим способом кодирования. Может кто-нибудь, пожалуйста, помогите мне.
Существует множество способов сортировки списка элементов. Вы используете сортировку вставки, которая является медленным методом сортировки. Вы можете просто использовать:
Arrays.sort(sArr);
который должен быть быстрее вашего сортировки вставки.
Если вы хотите узнать больше об алгоритмах сортировки: wikipedia
Comparator<String>
. И, вероятно, вам также следует оценить производительность алгоритма, используемого для сравнения элементов. Использование памятки в этом случае может даже ускорить это.
Кажется, есть две проблемы с кодом. Первое:
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));
Ну, причина, почему ваш вид занимает так много времени, заключается в том, что вы не используете эффективный алгоритм сортировки. Обычно, когда вы сортируете большое количество данных/записей/и т.д., Вы хотите определить алгоритм или решение, которое лучше всего работает с тем, что у вас есть.
В настоящее время у вашего алгоритма есть время выполнения 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()
Вы можете использовать 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);
}
}
Ваш код опирается на множество операций со строками. Строки неизменны в 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 содержит упорядоченный порядок значений.
Arrays.sort
...split("\\s")
в каждом сравнении (это довольно дорогой вызов). Вместо этого создайте отдельный класс, в котором вы будете хранить свои значения.