Алгоритм сложности O(n),язык по java
У меня есть некий файл CSV,откуда я построчно читаю данные(в файле каждая строка из себя представляет объект класса продукт) и кладу в уже специально реализованную коллекцию,которая сама сортирует продукты по цене и также есть установленное максимальное количество элементов в коллекции.Задача такая,нужно найти некое число самых низких по цене продуктов.Я правильно понимаю что алгоритм сложности здесь O(n) где n это количество строк(то есть продуктов) в файле??Я могу считать чтение и добавление одним шагом в этом алгоритме?и в конце получить уже коллекцию самых низких продуктов каким количеством нужно.На самом деле нужно написать алгоритм поиска чтобы сложность была O(n*log(m)) где n это количество продуктов в файле,а m это количество продуктов с минимальной ценой.Я не могу понять как реализовать алгоритм который бы соответствовал этой сложности,то есть нужно реализовать так что например если в файле миллион продуктов а нам нужно самые низкие по цене 32 продукта было O(n*5) а если нужно самые низкие по цене 64 продукта было O(n*6).В итоге чтобы сложность зависела от конкретного числа нужных продуктов низких по цене
Ответы (3 шт):
Может я что-то неправильно понял, но для этого есть комментарии, в которых можно уточнить... Я бы решил примерно так. если вы знаете , какое количество продуктов вам нужно получить и вычитываете пообъектно данные, то вам не надо хранить все и тем более сортировать накопленные объекты (их может быть довольно много). вам достаточно иметь в памяти то количество элементов, которое требуется от вас, например 5 с минимальной ценой. тогда каждый последующий полученный из файла продукт можно сравнивать с продуктом с максимальной ценой в множестве и подменить его, если необходимо. это должно работать достаточно быстро, потому как множества не ищут перебором, а по хешу, кроме того, размер вашего множества никогда не будет превышать размер, равный необходимому вам количеству элементов. это одновременно значит, что вы фактически не зависите от объема данных, которые находятся в исходном списке. вам нужно просто читать построчно (пообъектно) и обрабатывать каждый объект, не накапливая ничего лишнего в памяти. реализация такова. есть интерфейс, имплементирующий компаратор для сравнения цены и абстрактный метод, возвращающий цену. наш класс, обрабатывающий данные, будет работать с наследниками этого интерфейса (так правильнее с точки зрения ооп)
@FunctionalInterface
public interface Pricable extends Comparable<Pricable>{
Long getPrice();
@Override
public default int compareTo(Pricable p) {
return this.getPrice().compareTo(p.getPrice());
}
}
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class PriceFounder <T extends Pricable>{
private final int capacity;
private final TreeSet<T> set;
public PriceFounder(int capacity) {
this.capacity = capacity;
this.set = new TreeSet<>(Comparator.naturalOrder());
}
public void add (T element) {
if (set.size()<capacity) set.add(element);
else if (set.last().getPrice()>element.getPrice()) {
set.remove(set.last());
set.add(element);
}
}
public Set<T> getElements(){
return set;
}
}
и теперь содаем класс для демонстрации
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class Main {
public static void main(String[] args) {
//создаем тестовую коллекцию из объектов, содержащих информацию о цене
List<Price> prices = new ArrayList<>();
Random r = new Random();
for (int i = 0; i < 10; i++) {
Price price = new Price(Long.valueOf(r.nextInt(100)));
prices.add(price);
System.out.println(price);
}
System.out.println("***********************************************");
//эмулируем пообъектное чтение из файла: при чтении каждого объекта вызываем метод add у объекта PriceFounder
PriceFounder priceFounder = new PriceFounder(5);
for (Price price : prices) {
priceFounder.add(price);
}
//смотри мрезультат
System.out.println(priceFounder.getElements());
}
@lombok.Data
@lombok.AllArgsConstructor
private static class Price implements Pricable {
private Long price;
}
}
Я правильно понимаю что алгоритм сложности здесь O(n) где n это количество строк(то есть продуктов) в файле??
Неправильно. Вставка в отсортированную коллекцию (с поддержанием сортировки) не может быть O(1). Скорее всего это O(lb(k)), где k - размер коллекции. Судя по описанию в вопросе, k=n. Значит итоговая сложность O(n*lb(n)).
нужно написать алгоритм поиска чтобы сложность была O(n*log(m))
Чтобы сделать k=m, надо просто удалять лишние элементы из коллекции.
Вот помесь си++ с псевдокодом:
multiset <item> cheap;
for (unsigned q=0; q<n; ++q)
{
cheap.insert(read_next_item());
if (cheap.size() > m) cheap.erase(cheap.end())
}
for (auto &x : cheap)
cout << x << endl;
Скорее всего в джаве нужная коллекция называется TreeSet.
В Java можно сделать через PriorityQueue. В комментариях вы писали, что используете TreeSet, но у него есть одна особенность, он не хранит элементы с одинаковыми ключами. Т.е если у двух ваших продуктов одинаковая цена, то в сете будет только один из этих элементов
class Product implements Comparable<Product> {
int price;
Product(int price) { this.price = price; }
int getPrice() { return price; }
@Override
public String toString() { return String.valueOf(price); }
@Override
public int compareTo(@NotNull Product o) { return Integer.compare(getPrice(), o.getPrice()); }
}
...
List<Product> getMinPriceProducts(int m, Iterator<Product> iterator) {
// сортировка по уменьшению, чтобы удалять max голову
PriorityQueue<Product> products = new PriorityQueue<>(Comparator.reverseOrder());
while (iterator.hasNext()) {
products.offer(iterator.next());
if (products.size() > m) products.remove();
}
List<Product> result = new ArrayList<>(products);
Collections.sort(result);
return result;
}
...
