Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
nestudent.ru_46905.doc
Скачиваний:
28
Добавлен:
12.09.2019
Размер:
2.07 Mб
Скачать

Очереди на основе связных списков

Совсем другой подход к реализации очередей состоит в использовании двусвязных списков. Для отслеживания начала и конца списка можно использовать сигнальные метки. Новые элементы добавляются в очередь перед меткой в конце очереди, а элементы, следующие за меткой начала очереди, удаляются. На рис. 3.7 показан двусвязный список, который используется в качестве очереди.

===========58-59

Добавлять и удалять элементы из двусвязного списка легко, поэтому в этом случае не потребуется применять сложных алгоритмов для изменения размера. Преимущество этого метода также в том, что он интуитивно понятнее по сравнению с циклической очередью на основе массива. Недостаток его в том, что для указателей связного списка NextCell и PrevCell требуется дополнительная память. В отношении занимаемой памяти очереди на основе связных списков немного менее эффективны, чем циклические списки.

Программа LinkedQ работает с очередью при помощи двусвязного списка. Введите строку, нажмите на кнопку Enter, чтобы добавить элемент в конец очереди. Нажмите на кнопку Leave для удаления элемента из очереди.

Программа LinkedQ2 аналогична программе LinkedQ, но она использует для управления очередью класс LinkedListqueue.

Применение коллекций в качестве очередей

Коллекции Visual Basic представляют собой очень простую форму очереди. Программа может использовать метод Add коллекции для добавления элемента в конец очереди, и метод Remove с параметром 1 для удаления первого элемента из очереди. Следующий код управляет очередью на основе коллекций:

Dim Queue As New Collection

Private Sub EnterQueue(value As String)

Queue.Add value

End Sub

Private Function LeaveQueue() As String

LeaveQueue = Queue.Item(1)

Queue.Remove 1

Еnd Function

@Рис. 3.7. Очередь на основе связного списка

=======60

Несмотря на то, что этот код очень прост, коллекции в действительности не предназначены для использования в качестве очередей. Они предоставляют дополнительные возможности, такие как ключи элементов, и поддержка этих дополнительных возможностей делает коллекции более медленными, чем другие реализации очередей. Тем не менее, очереди на основе коллекций настолько просты, что они могут быть приемлемым выбором для приложений, в которых производительность не является проблемой.

Программа CollectQ демонстрирует очередь на основе коллекций.

Приоритетные очереди

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

Некоторые операционные системы использую приоритетные очереди для планирования заданий. В операционной системе UNIX все процессы имеют разные приоритеты. Когда процессор освобождается, выбирается готовый к исполнению процесс с наивысшим приоритетом. Процессы с более низким приоритетом должны ждать завершения или блокировки (например, при ожидании внешнего события, такого как чтение данных с диска) процессов с более высокими приоритетами.

Концепция приоритетных очередей также используется при управлении авиаперевозками. Наивысший приоритет имеют самолеты, у которых кончается топливо во время посадки. Второй приоритет имеют самолеты, заходящие на посадку. Третий приоритет имеют самолеты, находящиеся на земле, так как они находятся в более безопасном положении, чем самолеты в воздухе. Приоритеты изменяются со временем, так как у самолетов, которые пытаются приземлиться, в конце концов, закончится топливо.

Простой способ организации приоритетной очереди — поместить все элементы в список. Если требуется удалить элемент из очереди, можно найти в списке элемент с наивысшем приоритетом. Чтобы добавить элемент в очередь, он помещается в начало списка. При использовании этого метода, для добавления нового элемента в очередь требуется только один шаг. Чтобы найти и удалить элемент с наивысшим приоритетом, требуется O(N) шагов, если очередь содержит N элементов.

Немного лучше была бы схема с использованием связного списка, в котором элементы были бы упорядочены в прямом или обратном порядке. Используемый в списке класс PriorityCell мог бы объявлять переменные следующим образом:

Public Priority As Integer ' Приоритет элемента.

Public NextCell As PriorityCell ' Указатель на следующий элемент.

Public Value As String ' Данные, нужные программе.

Чтобы добавить элемент в очередь, нужно найти его правильное положение в списке и поместить его туда. Чтобы упростить поиск положения элемента, можно использовать сигнальные метки в начале и конце списка, присвоив им соответствующие приоритеты. Например, если элементы имеют приоритеты от 0 до 100, можно присвоить метке начала приоритет 101 и метке конца — приоритет ‑1. Приоритеты всех реальных элементов будут находиться между этими значениями.

На рис. 3.8 показана приоритетная очередь, реализованная на основе связного списка.

=====61

@Рис. 3.8. Приоритетная очередь на основе связного списка

Следующий фрагмент кода показывает ядро этой процедуры поиска:

Dim cell As PriorityCell

Dim nxt As PriorityCell

' Найти место элемента в списке.

cell = TopSentinel

nxt = cell.NextCell

Do While cell.Priority > new_priority

cell = nxt

nxt = cell.NextCell

Loop

' Вставить элемент после ячейки в списке.

:

Для удаления из списка элемента с наивысшим приоритетом, просто удаляется элемент после сигнальной метки начала. Так как список отсортирован в порядке приоритетов, первый элемент всегда имеет наивысший приоритет.

Добавление нового элемента в эту очередь занимает в среднем N/2 шагов. Иногда новый элемент будет оказываться в начале списка, иногда ближе к концу, но в среднем он будет оказываться где‑то в середине. Простая очередь на основе списка требовала O(1) шагов для добавления нового элемента и O(N) шагов для удаления элементов с наивысшим приоритетом из очереди. Версия на основе упорядоченного связного списка требует O(N) шагов для добавления элемента и O(1) шагов для удаления верхнего элемента. Обеим версиям требует O(N) шагов для одной из этих операций, но в случае упорядоченного связного списка в среднем требуется только (N/2) шагов.

Программа PriList использует упорядоченный связный список для работы с приоритетной очередью. Вы можете задать приоритет и значение элемента данных и нажать кнопку Enter для добавления его в приоритетную очередь. Нажмите на кнопку Leave для удаления из очереди элемента с наивысшим приоритетом.

Программа PriList2 аналогична программе PriList, но она использует для управления очередью класс LinkedPriorityQueue.

========63

Затратив еще немного усилий, можно построить приоритетную очередь, в которой добавление и удаление элемента потребуют порядка O(log(N)) шагов. Для очень больших очередей, ускорение работы может стоить этих усилий. Этот тип приоритетных очередей использует структуры данных в виде пирамиды, которые также применяются в алгоритме пирамидальной сортировки. Пирамиды и приоритетные очереди на их основе обсуждаются более подробно в 9 главе.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]