Алгоритм сложности 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;
    }
}

введите сюда описание изображения

→ Ссылка
Автор решения: Qwertiy

Я правильно понимаю что алгоритм сложности здесь 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.

→ Ссылка
Автор решения: IR42

В 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;
}
...
→ Ссылка