PriorityQueue, принципы работы и внутреннее устройство
PriorityQueue — это класс из пакета java.util, который реализует интерфейс Queue. В отличие от обычной очереди (FIFO), PriorityQueue основана на приоритетах элементов. Приоритет определяется с помощью естественного порядка элементов или через предоставленный компаратор.
В этом примере PriorityQueue автоматически упорядочивает элементы, так что при удалении элементов они извлекаются в порядке возрастания: 1, 3, 4.
Принципы работы PriorityQueue
Естественный порядок или компаратор: Элементы могут упорядочиваться на основе их естественного порядка (если элементы реализуют интерфейс Comparable) или на основе компаратора, предоставленного при создании очереди.
Бинарная куча (Binary Heap): Внутренняя реализация PriorityQueue основана на бинарной куче, которая является частично упорядоченным двоичным деревом. Это позволяет эффективно добавлять элементы и извлекать минимальный элемент.
Время выполнения операций: Основные операции PriorityQueue (вставка, удаление минимального элемента) выполняются за логарифмическое время O(log n), где n — количество элементов в очереди.
Внутреннее устройство PriorityQueue
PriorityQueue использует массив для хранения элементов, которые упорядочиваются в соответствии с правилами бинарной кучи. Дочерние элементы имеют более низкий приоритет по сравнению с родительскими элементами.
Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://www.baeldung.com/java-priorityqueue
https://sky.pro/media/ispolzovanie-priorityqueue-v-java/
#Java #Training #Medium #PriorityQueue
PriorityQueue — это класс из пакета java.util, который реализует интерфейс Queue. В отличие от обычной очереди (FIFO), PriorityQueue основана на приоритетах элементов. Приоритет определяется с помощью естественного порядка элементов или через предоставленный компаратор.
import java.util.PriorityQueue;
public class PriorityQueueExample {
public static void main(String[] args) {
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
priorityQueue.add(4);
priorityQueue.add(1);
priorityQueue.add(3);
while (!priorityQueue.isEmpty()) {
System.out.println(priorityQueue.poll());
}
}
}
В этом примере PriorityQueue автоматически упорядочивает элементы, так что при удалении элементов они извлекаются в порядке возрастания: 1, 3, 4.
Принципы работы PriorityQueue
Естественный порядок или компаратор: Элементы могут упорядочиваться на основе их естественного порядка (если элементы реализуют интерфейс Comparable) или на основе компаратора, предоставленного при создании очереди.
Бинарная куча (Binary Heap): Внутренняя реализация PriorityQueue основана на бинарной куче, которая является частично упорядоченным двоичным деревом. Это позволяет эффективно добавлять элементы и извлекать минимальный элемент.
Время выполнения операций: Основные операции PriorityQueue (вставка, удаление минимального элемента) выполняются за логарифмическое время O(log n), где n — количество элементов в очереди.
Внутреннее устройство PriorityQueue
PriorityQueue использует массив для хранения элементов, которые упорядочиваются в соответствии с правилами бинарной кучи. Дочерние элементы имеют более низкий приоритет по сравнению с родительскими элементами.
public class PriorityQueue<E> extends AbstractQueue<E> implements Serializable {
private static final int DEFAULT_INITIAL_CAPACITY = 11;
private Object[] queue;
private int size;
private final Comparator<? super E> comparator;
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
public PriorityQueue(int initialCapacity) {
this(initialCapacity, null);
}
public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) {
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
// Основные методы: add, poll, offer, remove, etc.
}
Ссылки на полезные статьи (спасибо авторам за проделанную работу) :
https://www.baeldung.com/java-priorityqueue
https://sky.pro/media/ispolzovanie-priorityqueue-v-java/
#Java #Training #Medium #PriorityQueue
Baeldung
Guide to Java PriorityQueue | Baeldung
A quick and practical guide to Java's PriorityQueue.
👍1
Основные методы PriorityQueue и примеры использования
add(E e):
Добавляет элемент в очередь. Если элемент null, выбрасывает NullPointerException.
offer(E e):
Добавляет элемент в очередь. Возвращает true, если элемент был успешно добавлен, и false в противном случае.
poll():
Возвращает и удаляет элемент с наивысшим приоритетом (минимальный элемент). Возвращает null, если очередь пуста.
peek():
Возвращает элемент с наивысшим приоритетом, но не удаляет его. Возвращает null, если очередь пуста.
remove(Object o):
Удаляет указанный элемент из очереди, если он присутствует. Возвращает true, если элемент был успешно удален, и false в противном случае.
contains(Object o):
Проверяет, присутствует ли указанный элемент в очереди. Возвращает true, если элемент найден, и false в противном случае.
size():
Возвращает количество элементов в очереди.
Примеры использования
Реализация задачи с приоритетом:
Использование с Comparator для обратного порядка:
Модель с приоритетом задач на основе времени выполнения:
#Java #Training #Medium #PriorityQueue
add(E e):
Добавляет элемент в очередь. Если элемент null, выбрасывает NullPointerException.
PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.add(10);
pq.add(20);
pq.add(15);
offer(E e):
Добавляет элемент в очередь. Возвращает true, если элемент был успешно добавлен, и false в противном случае.
pq.offer(5);
poll():
Возвращает и удаляет элемент с наивысшим приоритетом (минимальный элемент). Возвращает null, если очередь пуста.
Integer top = pq.poll(); // Возвращает 5 и удаляет его из очереди
peek():
Возвращает элемент с наивысшим приоритетом, но не удаляет его. Возвращает null, если очередь пуста.
Integer top = pq.peek(); // Возвращает 10, но не удаляет его
remove(Object o):
Удаляет указанный элемент из очереди, если он присутствует. Возвращает true, если элемент был успешно удален, и false в противном случае.
boolean removed = pq.remove(15); // Удаляет элемент 15
contains(Object o):
Проверяет, присутствует ли указанный элемент в очереди. Возвращает true, если элемент найден, и false в противном случае.
boolean contains = pq.contains(20); // Проверяет наличие элемента 20
size():
Возвращает количество элементов в очереди.
int size = pq.size(); // Возвращает количество элементов в очереди
Примеры использования
Реализация задачи с приоритетом:
import java.util.PriorityQueue;
import java.util.Comparator;
class Task {
private String name;
private int priority;
public Task(String name, int priority) {
this.name = name;
this.priority = priority;
}
public int getPriority() {
return priority;
}
@Override
public String toString() {
return name + ": " + priority;
}
}
class TaskComparator implements Comparator<Task> {
public int compare(Task t1, Task t2) {
return Integer.compare(t1.getPriority(), t2.getPriority());
}
}
public class TaskScheduler {
public static void main(String[] args) {
PriorityQueue<Task> taskQueue = new PriorityQueue<>(new TaskComparator());
taskQueue.add(new Task("Task 1", 2));
taskQueue.add(new Task("Task 2", 1));
taskQueue.add(new Task("Task 3", 3));
while (!taskQueue.isEmpty()) {
System.out.println(taskQueue.poll());
}
}
}
Использование с Comparator для обратного порядка:
PriorityQueue<Integer> reversePQ = new PriorityQueue<>(Comparator.reverseOrder());
reversePQ.add(10);
reversePQ.add(20);
reversePQ.add(15);
while (!reversePQ.isEmpty()) {
System.out.println(reversePQ.poll());
}
Модель с приоритетом задач на основе времени выполнения:
import java.util.PriorityQueue;
class Job implements Comparable<Job> {
private String jobName;
private int executionTime;
public Job(String jobName, int executionTime) {
this.jobName = jobName;
this.executionTime = executionTime;
}
@Override
public int compareTo(Job other) {
return Integer.compare(this.executionTime, other.executionTime);
}
@Override
public String toString() {
return jobName + ": " + executionTime;
}
}
public class JobScheduler {
public static void main(String[] args) {
PriorityQueue<Job> jobQueue = new PriorityQueue<>();
jobQueue.add(new Job("Job 1", 30));
jobQueue.add(new Job("Job 2", 10));
jobQueue.add(new Job("Job 3", 20));
while (!jobQueue.isEmpty()) {
System.out.println(jobQueue.poll());
}
}
}
#Java #Training #Medium #PriorityQueue
Раздел 6. Коллекции в Java
Глава 4. Queue и Deque
Реализации: PriorityQueue, LinkedList как очередь. Применение: обработка задач, хранение заявок
Интерфейс Queue<E> имеет несколько реализаций в JCF, каждая оптимизирована под разные сценарии. Сегодня фокус на PriorityQueue и LinkedList (как Queue). Эти реализации демонстрируют разнообразие: от строгого FIFO до приоритетной обработки.
LinkedList<E> как Queue
LinkedList — это двусвязный список (doubly-linked list), который реализует Queue<E> (а также List<E> и Deque<E>). Как очередь, она идеальна для FIFO: добавление в конец, извлечение из начала.
Особенности:
FIFO: Строго соблюдается порядок добавления.
Уникальность: Нет, дубликаты разрешены.
Null: Разрешен (LinkedList позволяет null элементы).
Big O: O(1) для offer (добавление в конец), poll (извлечение из начала), peek (просмотр начала). Contains — O(n), так как перебор списка.
Внутренняя работа: Каждый элемент — узел (node) с ссылками на prev и next. Добавление — создание узла и обновление ссылок. Извлечение — удаление первого узла и сдвиг ссылок.
Нюансы:
Эффективна для частых вставок/удалений в концах (O(1)), но медленная для середины (O(n)).
Память: Выше, чем у ArrayDeque (из-за ссылок на prev/next).
Thread-safety: Нет — для многопоточности используйте BlockingQueue.
Дополнительно: Как Deque, поддерживает добавление/извлечение с обоих концов (об этом в следующем уроке).
Когда использовать: Для простых FIFO-очередей с небольшим размером, или когда нужна универсальность (Queue + List).
Пример кода для LinkedList как Queue:
PriorityQueue<E>
PriorityQueue — это приоритетная очередь на основе кучи (binary heap, min-heap по умолчанию). Она не следует FIFO, а извлекает элементы по приоритету (минимальный первый для натуральных типов).
Особенности:
FIFO: Нет — приоритетный порядок (по Comparable или Comparator).
Уникальность: Нет, дубликаты разрешены.
Null: Не разрешен (NullPointerException).
Big O: O(log n) для offer (вставка в кучу), poll (извлечение минимума с перестройкой), peek — O(1). Contains — O(n), так как перебор.
Внутренняя работа: Хранит элементы в массиве как бинарную кучу. При добавлении/извлечении перестраивает кучу (heapify) для поддержания свойства: родитель <= дети. Приоритет определяется compareTo() или Comparator.
Нюансы:
Порядок итерации: Не гарантирован (куча не sorted list).
Comparator: Передайте при создании: new PriorityQueue<>((a, b) -> b - a) для max-heap.
Размер: Resizable, initial capacity 11.
Thread-safety: Нет — используйте PriorityBlockingQueue для потоков.
Custom объекты: Должны реализовывать Comparable<E> или предоставить Comparator, иначе ClassCastException.
Когда использовать: Для задач с приоритетами (например, планировщик задач, Dijkstra алгоритм).
#Java #для_новичков #beginner #Collections #PriorityQueue #LinkedList
Глава 4. Queue и Deque
Реализации: PriorityQueue, LinkedList как очередь. Применение: обработка задач, хранение заявок
Интерфейс Queue<E> имеет несколько реализаций в JCF, каждая оптимизирована под разные сценарии. Сегодня фокус на PriorityQueue и LinkedList (как Queue). Эти реализации демонстрируют разнообразие: от строгого FIFO до приоритетной обработки.
LinkedList<E> как Queue
LinkedList — это двусвязный список (doubly-linked list), который реализует Queue<E> (а также List<E> и Deque<E>). Как очередь, она идеальна для FIFO: добавление в конец, извлечение из начала.
Особенности:
FIFO: Строго соблюдается порядок добавления.
Уникальность: Нет, дубликаты разрешены.
Null: Разрешен (LinkedList позволяет null элементы).
Big O: O(1) для offer (добавление в конец), poll (извлечение из начала), peek (просмотр начала). Contains — O(n), так как перебор списка.
Внутренняя работа: Каждый элемент — узел (node) с ссылками на prev и next. Добавление — создание узла и обновление ссылок. Извлечение — удаление первого узла и сдвиг ссылок.
Нюансы:
Эффективна для частых вставок/удалений в концах (O(1)), но медленная для середины (O(n)).
Память: Выше, чем у ArrayDeque (из-за ссылок на prev/next).
Thread-safety: Нет — для многопоточности используйте BlockingQueue.
Дополнительно: Как Deque, поддерживает добавление/извлечение с обоих концов (об этом в следующем уроке).
Когда использовать: Для простых FIFO-очередей с небольшим размером, или когда нужна универсальность (Queue + List).
Пример кода для LinkedList как Queue:
javaimport java.util.LinkedList;
import java.util.Queue;
public class Main {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>();
queue.offer("Задача 1"); // Добавление в конец
queue.offer("Задача 2");
queue.offer("Задача 3");
System.out.println(queue); // [Задача 1, Задача 2, Задача 3] — FIFO порядок
System.out.println(queue.peek()); // Задача 1 (просмотр)
System.out.println(queue.poll()); // Задача 1 (извлечение)
System.out.println(queue); // [Задача 2, Задача 3]
queue.offer(null); // Разрешен null
System.out.println(queue.poll()); // Задача 2
}
}
Вывод: Показывает FIFO — элементы извлекаются в порядке добавления, null разрешен.
PriorityQueue<E>
PriorityQueue — это приоритетная очередь на основе кучи (binary heap, min-heap по умолчанию). Она не следует FIFO, а извлекает элементы по приоритету (минимальный первый для натуральных типов).
Особенности:
FIFO: Нет — приоритетный порядок (по Comparable или Comparator).
Уникальность: Нет, дубликаты разрешены.
Null: Не разрешен (NullPointerException).
Big O: O(log n) для offer (вставка в кучу), poll (извлечение минимума с перестройкой), peek — O(1). Contains — O(n), так как перебор.
Внутренняя работа: Хранит элементы в массиве как бинарную кучу. При добавлении/извлечении перестраивает кучу (heapify) для поддержания свойства: родитель <= дети. Приоритет определяется compareTo() или Comparator.
Нюансы:
Порядок итерации: Не гарантирован (куча не sorted list).
Comparator: Передайте при создании: new PriorityQueue<>((a, b) -> b - a) для max-heap.
Размер: Resizable, initial capacity 11.
Thread-safety: Нет — используйте PriorityBlockingQueue для потоков.
Custom объекты: Должны реализовывать Comparable<E> или предоставить Comparator, иначе ClassCastException.
Когда использовать: Для задач с приоритетами (например, планировщик задач, Dijkstra алгоритм).
#Java #для_новичков #beginner #Collections #PriorityQueue #LinkedList
👍1
Пример кода для PriorityQueue:
Применение очередей: Обработка задач, хранение заявок
Очереди идеальны для сценариев последовательной обработки.
Обработка задач (Task Processing):
Пример: Планировщик задач, где задачи добавляются в очередь и обрабатываются по порядку (FIFO с LinkedList) или по приоритету (PriorityQueue).
Нюанс: В многопоточных системах (например, Thread pool) используйте BlockingQueue для безопасного poll.
Пример кода (простой обработчик):
Хранение заявок (Request Storage):
Пример: Сервер хранит входящие заявки в очередь для последовательной обработки (например, HTTP requests).
С PriorityQueue: Заявки по срочности (high-priority first).
Нюанс: Для реальных систем используйте BlockingQueue (offer/poll с блокировкой при пустой/полной).
Пример кода (приоритетные заявки):
Полезные советы для новичков
LinkedList для простоты: Универсальна для FIFO, легко добавить Deque-функции.
PriorityQueue для приоритетов: Передавайте Comparator для custom порядка (например, max-heap).
Custom классы: Реализуйте Comparable для PriorityQueue, или используйте Comparator.
Пустая очередь: Проверяйте isEmpty() перед poll, или используйте null от poll.
Итерация: For-each для просмотра, но не модифицируйте.
#Java #для_новичков #beginner #Collections #PriorityQueue #LinkedList
javaimport java.util.PriorityQueue;
import java.util.Queue;
public class Main {
public static void main(String[] args) {
Queue<Integer> queue = new PriorityQueue<>();
queue.offer(3);
queue.offer(1);
queue.offer(2);
System.out.println(queue); // [1, 3, 2] — min в начале, но итерация не sorted
System.out.println(queue.peek()); // 1 (минимальный)
System.out.println(queue.poll()); // 1
System.out.println(queue); // [2, 3]
// Max-heap с Comparator
Queue<Integer> maxQueue = new PriorityQueue<>((a, b) -> b - a);
maxQueue.offer(3);
maxQueue.offer(1);
maxQueue.offer(2);
System.out.println(maxQueue.poll()); // 3 (максимальный)
// queue.offer(null); // NPE
}
}
Вывод: Элементы извлекаются по приоритету, не по порядку добавления.
Применение очередей: Обработка задач, хранение заявок
Очереди идеальны для сценариев последовательной обработки.
Обработка задач (Task Processing):
Пример: Планировщик задач, где задачи добавляются в очередь и обрабатываются по порядку (FIFO с LinkedList) или по приоритету (PriorityQueue).
Нюанс: В многопоточных системах (например, Thread pool) используйте BlockingQueue для безопасного poll.
Пример кода (простой обработчик):
javaimport java.util.LinkedList;
import java.util.Queue;
public class TaskProcessor {
private Queue<String> tasks = new LinkedList<>();
public void addTask(String task) {
tasks.offer(task);
}
public void processTasks() {
while (!tasks.isEmpty()) {
String task = tasks.poll();
System.out.println("Обработка: " + task);
}
}
}
public class Main {
public static void main(String[] args) {
TaskProcessor processor = new TaskProcessor();
processor.addTask("Задача 1");
processor.addTask("Задача 2");
processor.processTasks(); // Обработка: Задача 1\nОбработка: Задача 2
}
}
Вывод: Задачи обрабатываются FIFO.
Хранение заявок (Request Storage):
Пример: Сервер хранит входящие заявки в очередь для последовательной обработки (например, HTTP requests).
С PriorityQueue: Заявки по срочности (high-priority first).
Нюанс: Для реальных систем используйте BlockingQueue (offer/poll с блокировкой при пустой/полной).
Пример кода (приоритетные заявки):
javaimport java.util.PriorityQueue;
import java.util.Queue;
class Request implements Comparable<Request> {
private String name;
private int priority; // 1 - высокий, 10 - низкий
public Request(String name, int priority) {
this.name = name;
this.priority = priority;
}
@Override
public int compareTo(Request other) {
return Integer.compare(this.priority, other.priority); // Min-heap по приоритету
}
public String getName() {
return name;
}
}
public class Main {
public static void main(String[] args) {
Queue<Request> requests = new PriorityQueue<>();
requests.offer(new Request("Заявка A", 5));
requests.offer(new Request("Заявка B", 1)); // Высокий приоритет
requests.offer(new Request("Заявка C", 3));
while (!requests.isEmpty()) {
System.out.println("Обработка: " + requests.poll().getName()); // Заявка B, Заявка C, Заявка A
}
}
}
Вывод: Заявки обрабатываются по приоритету.
Полезные советы для новичков
LinkedList для простоты: Универсальна для FIFO, легко добавить Deque-функции.
PriorityQueue для приоритетов: Передавайте Comparator для custom порядка (например, max-heap).
Custom классы: Реализуйте Comparable для PriorityQueue, или используйте Comparator.
Пустая очередь: Проверяйте isEmpty() перед poll, или используйте null от poll.
Итерация: For-each для просмотра, но не модифицируйте.
#Java #для_новичков #beginner #Collections #PriorityQueue #LinkedList
👍1