Реферат: VB, MS Access, VC++, Delphi, Builder C++ принципы(технология), алгоритмы программирования
С другой стороны, применение псевдоуказателей не столь интуитивно, как применение ссылок. Это может усложнить разработку и отладку сложных алгоритмов, таких как алгоритмы сетей или сбалансированных деревьев.
@Рис. 2.11. Двоичное дерево
========43
@Рис. 2.12. Связные структуры
Программа FakeList управляет связным списком, используя псевдоуказатели. Она создает массив простых структур данных для хранения ячеек списка. Программа аналогична программе LnkList1, но использует псевдоуказатели.
Следующий код демонстрирует, как программа FakeList создает массив клеточных структур:
' Структура данных ячейки.
Type FakeCell
Value As String
NextCell As Integer
End Type
' Массив ячеек связного списка.
Global Cells(0 To 100) As FakeCell
' Сигнальная метка списка.
Global Sentinel As Integer
Поскольку псевдоуказатели — это не ссылки, а просто целые числа, программа не может использовать значение Nothing для маркировки конца списка. Программа FakeList использует постоянную END_OF_LIST, значение которой равно -32.767 для обозначения пустого указателя.
Для облегчения обнаружения неиспользуемых ячеек, программа FakeList также использует специальный «мусорный» список, содержащий неиспользуемые ячейки. Следующий код демонстрирует инициализацию пустого связного списка. В нем сигнальная метка NextCell принимает значение END_OF_LIST. Затем она помещает неиспользуемые ячейки в «мусорный» список.
========44
' Связный список неиспользуемых ячеек.
Global TopGarbage As Integer
Public Sub InitializeList()
Dim i As Integer
Sentinel = 0
Cells(Sentinel).NextCell = END_OF_LIST
' Поместить все остальные ячейки в «мусорный» список.
For i = 1 To UBound (Cells) - 1
Cells(i).NextCell = i + 1
Next i
Cells(UBound(Cells)).NextCell = END_OF_LIST
TopGarbage = 1
End Sub
При добавлении элемента к связному списку, программа использует первую доступную ячейку из «мусорного» списка, инициализирует поле ячейки Value и вставляет ячейку в список. Следующий код показывает, как программа добавляет элемент после выбранного:
Private Sub CmdAddAfter_Click()
Dim ptr As Integer
Dim position As Integer
Dim new_cell As Integer
' Найти место вставки.
ptr = Sentinel
position = Selectedlndex
Do While position > 0
position = position - 1
ptr = Cells(ptr).NextCell
Loop
' Выбрать новую ячейку из «мусорного» списка.
new_cell = TopGarbage
TopGarbage = Cells(TopGarbage).NextCell
' Вставить элемент.
Cells (new_cell).Value = NewItem.Text
Cells(new_cell).NextCell = Cells(ptr).NextCell
Cells(ptr).NextCell = new_cell
NumItems = NumItems + 1
DisplayList
SelectItem SelectedIndex + 1 ' Выбрать новый элемент.
NewItem.Text = ""
NewItem.SetFocus
CmdClearList.Enabled = True
End Sub
После удаления ячейки из списка, программа FakeList помещает удаленную ячейку в «мусорный» список, чтобы ее затем можно было легко использовать:
Private Sub CmdRemoveAfter_Click()
Dim ptr As Integer
Dim target As Integer
Dim position As Integer
If SelectedIndex < 0 Then Exit Sub
' Найти элемент.
ptr = Sentinel
position = SelectedIndex
Do While position > 0
position = position - 1
ptr = Cells(ptr).NextCell
Loop
' Пропустить следующий элемент.
target = Cells(ptr).NextCell
Cells(ptr).NextCell = Cells(target).NextCell
NumItems = NumItems - 1
' Добавить удаленную ячейку в «мусорный» список.
Cells(target).NextCell = TopGarbage
TopGarbage = target
SelectItem Selectedlndex ' Снова выбрать элемент.
DisplayList
CmdClearList.Enabled = NumItems > 0
NewItem.SetFocus
End Sub
Применение псевдоуказателей обычно обеспечивает лучшую производительность, но является более сложным. Поэтому имеет смысл сначала создать приложение, используя ссылки на объекты. Затем, если вы обнаружите, что программа значительную часть времени тратит на манипулирование ссылками, вы можете, если необходимо, преобразовать ее с использованием псевдоуказателей.
=======45-46
Резюме
Используя ссылки на объекты, вы можете создавать гибкие структуры данных, такие как связные списки, циклические связные списки и двусвязные списки. Эти списки позволяют легко добавлять и удалять элементы из любого места списка.
Добавляя дополнительные ссылки к классу ячеек, можно превратить двусвязный список в многопоточный. Развивая и дальше эти идеи, можно создавать экзотические структуры данных, включая разреженные массивы, деревья, хэш‑таблицы и сети. Они подробно описываются в следующих главах.
========47
Глава 3. Стеки и очередиВ этой главе продолжается обсуждение списков, начатое во 2 главе, и описываются две особых разновидности списков: стеки и очереди. Стек — это список, в котором добавление и удаление элементов осуществляется с одного и того же конца списка. Очередь — это список, в котором элементы добавляются в один конец списка, а удаляются с противоположного конца. Многие алгоритмы, включая некоторые из представленных в следующих главах, используют стеки и очереди.
Стеки
Стек (stack) — это упорядоченный список, в котором добавление и удаление элементов всегда происходит на одном конце списка. Можно представить стек как стопку предметов на полу. Вы можете добавлять элементы на вершину и удалять их оттуда, но не можете добавлять или удалять элементы из середины стопки.
Стеки часто называют списками типа первый вошел — последний вышел (Last‑In‑First‑Out list). По историческим причинам, добавление элемента в стек называется проталкиванием (pushing) элемента в стек, а удаление элемента из стека — выталкиванием (popping) элемента из стека.
Первая реализация простого списка на основе массива, описанная в начале 2 главы, является стеком. Для отслеживания вершины списка используется счетчик. Затем этот счетчик используется для вставки или удаления элемента из вершины списка. Небольшое изменение — это новая процедура Pop, которая удаляет элемент из списка, одновременно возвращая его значение. При этом другие процедуры могут извлекать элемент и удалять его из списка за один шаг. Кроме этого изменения, следующий код совпадает с кодом, приведенным во 2 главе.
Dim Stack() As Variant
Dim StackSize As Variant
Sub Push(value As Variant)
StackSize = StackSize + 1
ReDim Preserve Stack(1 To StackSize)
Stack(StackSize) = value
End Sub
Sub Pop(value As Variant)
value = Stack(StackSize)
StackSize = StackSize - 1
ReDim Preserve Stack(1 To StackSize)
End Sub
=====49
Все предыдущие рассуждения о списках также относятся к этому виду реализации стеков. В частности, можно сэкономить время, если не изменять размер при каждом добавлении или выталкивании элемента. Программа SimList на описанная во 2 главе, демонстрирует этот вид простой реализации списков.
Программы часто используют стеки для хранения последовательности элементов, с которыми программа будет работать до тех пор, пока стек не опустеет. Действия с одним из элементов может приводить к тому, что другие будут проталкиваться в стек, но, в конце концов, они все будут удалены из стека. В качестве простого примера можно привести алгоритм обращения порядка элементов массива. При этом все элементы последовательно проталкиваются в стек. Затем все элементы выталкиваются из стека в обратном порядке и записываются обратно в массив.
Dim List() As Variant
Dim NumItems As Integer
' Инициализация массива.
:
' Протолкнуть элементы в стек.
For I = 1 To NumItems
Push List(I)
Next I
' Вытолкнуть элементы из стека обратно в массив.
For I = 1 To NumItems
Pop List(I)
Next I
В этом примере, длина стека может многократно изменяться до того, как, в конце концов, он опустеет. Если известно заранее, насколько большим должен быть массив, можно сразу создать достаточно большой стек. Вместо изменения размера стека по мере того, как он растет и уменьшается, можно отвести под него память в начале работы и уничтожить его после ее завершения.
Следующий код позволяет создать стек, если заранее известен его максимальный размер. Процедура Pop не изменяет размер массива. Когда программа заканчивает работу со стеком, она должна вызвать процедуру EmptyStack для освобождения занятой под стек памяти.
======50
Const WANT_FREE_PERCENT = .1 ' 10% свободного пространства.
Const MIN_FREE = 10 ' Минимальный размер.
Global Stack() As Integer ' Стековый массив.
Global StackSize As Integer ' Размер стекового массива.
Global Lastltem As Integer ' Индекс последнего элемента.
Sub PreallocateStack(entries As Integer)
StackSize = entries
ReDim Stack(1 To StackSize)
End Sub
Sub EmptyStack()
StackSize = 0
LastItem = 0
Erase Stack ' Освободить память, занятую массивом.
End Sub
Sub Push(value As Integer)
LastItem = LastItem + 1
If LastItem > StackSize Then ResizeStack
Stack(LastItem) = value
End Sub
Sub Pop(value As Integer)
value = Stack(LastItem)
LastItem = LastItem - 1
End Sub
Sub ResizeStack()
Dim want_free As Integer
want_free = WANT_FREE_PERCENT * LastItem
If want_free < MIN_FREE Then want_free = MIN_FREE
StackSize = LastItem + want_free
ReDim Preserve Stack(1 To StackSize)
End Sub
Этот вид реализации стеков достаточно эффективен в Visual Basic. Стек не расходует понапрасну память, и не слишком часто изменяет свой размер, особенно если сразу известно, насколько большим он должен быть.
=======51
Множественные стеки
В одном массиве можно создать два стека, поместив один в начале массива, а другой — в конце. Для двух стеков используются отдельные счетчики длины стека Top, и стеки растут навстречу друг другу, как показано на рис. 3.1. Этот метод позволяет двум стекам расти, занимая одну и ту же область памяти, до тех пор, пока они не столкнутся, когда массив заполнится.
К сожалению, менять размер этих стеков непросто. При увеличении массива необходимо сдвигать все элементы в верхнем стеке, чтобы выделять память под новые элементы в середине. При уменьшении массива, необходимо вначале сдвинуть элементы верхнего стека, перед тем, как менять размер массива. Этот метод также сложно масштабировать для оперирования более чем двумя стеками.
Связные списки предоставляют более гибкий метод построения множественных стеков. Для проталкивания элемента в стек, он помещается в начало связного списка. Для выталкивания элемента из стека, удаляется первый элемент из связного списка. Так как элементы добавляются и удаляются только в начале списка, для реализации стеков такого типа не требуется применение сигнальных меток или двусвязных списков.
Основной недостаток применения стеков на основе связных списков состоит в том, что они требуют дополнительной памяти для хранения указателей NextCell. Для стека на основе массива, содержащего N элементов, требуется всего 2*N байт памяти (по 2 байта на целое число). Тот же стек, реализованный на основе связного списка, потребует дополнительно 4*N байт памяти для указателей NextCell, увеличивая размер необходимой памяти втрое.
Программа Stack использует несколько стеков, реализованных в виде связных списков. Используя программу, можно вставлять и выталкивать элементы из каждого из этих списков. Программа Stack2 аналогична этой программе, но она использует класс LinkedListStack для работы со стеками.
Очереди
Упорядоченный список, в котором элементы добавляются к одному концу списка, а удаляются с другой стороны, называется очередью (queue). Группа людей, ожидающих обслуживания в магазине, образует очередь. Вновь прибывшие подходят сзади. Когда покупатель доходит до начала очереди, кассир его обслуживает. Из‑за их природы, очереди иногда называют списками типа первый вошел — первый вышел (First‑In‑First‑Out list).
@Рис. 3.1. Два стека в одном массиве
=======52
Можно реализовать очереди в Visual Basic, используя методы типа использованных для организации простых стеков. Создадим массив, и при помощи счетчиков будем определять положение начала и конца очереди. Значение переменной QueueFront дает индекс элемента в начале очереди. Переменная QueueBack определяет, куда должен быть добавлен очередной элемент очереди. По мере того как новые элементы добавляются в очередь и покидают ее, размер массива, содержащего очередь, изменяется так, что он растет на одном конце и уменьшается на другом.
Global Queue() As String ' Массив очереди.
Global QueuePront As Integer ' Начало очереди.
Global QueueBack As Integer ' Конец очереди.
Sub EnterQueue(value As String)
ReDim Preserve Queue(QueueFront To QueueBack)
Queue(QueueBack) = value
QueueBack = QueueBack + 1
End Sub
Sub LeaveQueue(value As String)
value = Queue(QueueFront)
QueueFront = QueueFront + 1
ReDim Preserve Queue (QueueFront To QueueBack - 1)
End Sub
К сожалению, Visual Basic не позволяет использовать ключевое слово Preserve в операторе ReDim, если изменяется нижняя граница массива. Даже если бы Visual Basic позволял выполнение такой операции, очередь при этом «двигалась» бы по памяти. При каждом добавлении или удалении элемента из очереди, границы массива увеличивались бы. После пропускания достаточно большого количества элементов через очередь, ее границы могли бы в конечном итоге стать слишком велики.
Поэтому, когда требуется увеличить размер массива, вначале необходимо переместить данные в начало массива. При этом может образоваться достаточное количество свободных ячеек в конце массива, так что увеличение размера массива может уже не понадобиться. В противном случае, можно воспользоваться оператором ReDim для увеличения или уменьшения размера массива.
Как и в случае со списками, можно повысить производительность, добавляя сразу несколько элементов при увеличении размера массива. Также можно сэкономить время, уменьшая размер массива, только когда он содержит слишком много неиспользуемых ячеек.
В случае простого списка или стека, элементы добавляются и удаляются на одном его конце. Если размер списка остается почти постоянным, его не придется изменять слишком часто. С другой стороны, так как элементы добавляются на одном конце очереди, а удаляются с другого конца, может потребоваться время от времени переупорядочивать очередь, даже если ее размер остается неизменным.
=====53
Const WANT_FREE_PERCENT = .1 ' 10% свободного пространства.
Const MIN_FREE = 10 ' Минимум свободных ячеек.
Global Queue() As String ' Массив очереди.
Global QueueMax As Integer ' Наибольший индекс массива.
Global QueueFront As Integer ' Начало очереди.
Global QueueBack As Integer ' Конец очереди.
Global ResizeWhen As Integer ' Когда увеличить размер массива.
' При инициализации программа должна установить QueueMax = -1
' показывая, что под массив еще не выделена память.
Sub EnterQueue(value As String)
If QueueBack > QueueMax Then ResizeQueue
Queue(QueueBack) = value
QueueBack = QueueBack + 1
End Sub
Sub LeaveQueue(value As String)
value = Queue(QueueFront)
QueueFront = QueueFront + 1
If QueueFront > ResizeWhen Then ResizeOueue
End Sub
Sub ResizeQueue()
Dim want_free As Integer
Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48