МЕНЮ


Фестивали и конкурсы
Семинары
Издания
О МОДНТ
Приглашения
Поздравляем

НАУЧНЫЕ РАБОТЫ


  • Инновационный менеджмент
  • Инвестиции
  • ИГП
  • Земельное право
  • Журналистика
  • Жилищное право
  • Радиоэлектроника
  • Психология
  • Программирование и комп-ры
  • Предпринимательство
  • Право
  • Политология
  • Полиграфия
  • Педагогика
  • Оккультизм и уфология
  • Начертательная геометрия
  • Бухучет управленчучет
  • Биология
  • Бизнес-план
  • Безопасность жизнедеятельности
  • Банковское дело
  • АХД экпред финансы предприятий
  • Аудит
  • Ветеринария
  • Валютные отношения
  • Бухгалтерский учет и аудит
  • Ботаника и сельское хозяйство
  • Биржевое дело
  • Банковское дело
  • Астрономия
  • Архитектура
  • Арбитражный процесс
  • Безопасность жизнедеятельности
  • Административное право
  • Авиация и космонавтика
  • Кулинария
  • Наука и техника
  • Криминология
  • Криминалистика
  • Косметология
  • Коммуникации и связь
  • Кибернетика
  • Исторические личности
  • Информатика
  • Инвестиции
  • по Зоология
  • Журналистика
  • Карта сайта
  • VB, MS Access, VC++, Delphi, Builder C++ принципы(технология), алгоритмы программирования

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

    удалить ячейку после нее или перечислить идущие за ней ячейки. Удалить саму

    ячейку, вставить новую ячейку перед ней или перечислить идущие перед ней

    ячейки уже не так легко. Тем не менее, небольшое изменение позволит

    облегчить и эти операции.

    Добавим новое поле указателя к каждой ячейке, которое указывает на

    предыдущую ячейку в списке. Используя это новое поле, можно легко создать

    двусвязный список (doubly linked list), который позволяет перемещаться

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

    перед другой ячейкой и перечислить ячейки в любом направлении.

    @Рис. 2.8. Двусвязный список

    ============37

    Класс DoubleListCell, который используется для таких типов списков, может

    объявлять переменные так:

    Public Value As Variant

    Public NextCell As DoubleListCell

    Public PrevCell As DoubleListCell

    Часто бывает полезно сохранять указатели и на начало, и на конец

    двусвязного списка. Тогда вы сможете легко добавлять элементы к любому из

    концов списка. Иногда также бывает полезно размещать сигнальные метки и в

    начале, и в конце списка. Тогда по мере работы со списком вам не нужно

    будет заботиться о том, работаете ли вы с началом, с серединой или с концом

    списка.

    На рис. 2.9 показан двусвязный список с сигнальными метками. На этом

    рисунке неиспользуемые указатели меток NextCell и PrevCell установлены в

    Nothing. Поскольку программа опознает концы списка, сравнивая значения

    указателей ячеек с сигнальными метками, и не проверяет, равны ли значения

    Nothing, установка этих значений равными Nothing не является абсолютно

    необходимой. Тем не менее, это признак хорошего стиля.

    Код для вставки и удаления элементов из двусвязного списка подобен

    приведенному ранее коду для односвязного списка. Процедуры нуждаются лишь в

    незначительных изменениях для работы с указателями PrevCell.

    @Рис. 2.9. Двусвязный список с сигнальными метками

    Теперь вы можете написать новые процедуры для вставки нового элемента до

    или после данного элемента, и процедуру удаления заданного элемента.

    Например, следующие подпрограммы добавляют и удаляют ячейки из двусвязного

    списка. Заметьте, что эти процедуры не нуждаются в доступе ни к одной из

    сигнальных меток списка. Им нужны только указатели на узел, который должен

    быть удален или добавлен и узел, соседний с точкой вставки.

    Public Sub RemoveItem(ByVal target As DoubleListCell)

    Dim after_target As DoubleListCell

    Dim before_target As DoubleListCell

    Set after_target = target.NextCell

    Set before_target = target.PrevCell

    Set after_target.NextCell = after_target

    Set after_target.PrevCell = before_target

    End Sub

    Sub AddAfter (new_Cell As DoubleListCell, after_me As DoubleListCell)

    Dim before_me As DoubleListCell

    Set before_me = after_me.NextCell

    Set after_me.NextCell = new_cell

    Set new_cell.NextCell = before_me

    Set before_me.PrevCell = new_cell

    Set new_cell.PrevCell = after_me

    End Sub

    Sub AddBefore(new_cell As DoubleListCell, before_me As DoubleListCell)

    Dim after_me As DoubleListCell

    Set after_me = before_me.PrevCell

    Set after_me.NextCell = new_cell

    Set new_cell.NextCell = before_me

    Set before_me.PrevCell = new_cell

    Set new_cell.PrevCell = after_me

    End Sub

    ===========39

    Если снова взглянуть на рис. 2.9, вы увидите, что каждая пара соседних

    ячеек образует циклическую ссылку. Это делает уничтожение двусвязного

    списка немного более сложной задачей, чем уничтожение односвязных или

    циклических списков. Следующий код приводит один из способов очистки

    двусвязного списка. Вначале указатели PrevCell всех ячеек устанавливаются

    равными Nothing, чтобы разорвать циклические ссылки. Это, по существу,

    превращает список в односвязный. Когда ссылки сигнальных меток

    устанавливаются в Nothing, все элементы освобождаются автоматически, так же

    как и в односвязном списке.

    Dim ptr As DoubleListCell

    ' Очистить указатели PrevCell, чтобы разорвать циклические ссылки.

    Set ptr = TopSentinel.NextCell

    Do While Not (ptr Is BottomSentinel)

    Set ptr.PrevCell = Nothing

    Set ptr = ptr.NextCell

    Loop

    Set TopSentinel.NextCell = Nothing

    Set BottomSentinel.PrevCell = Nothing

    Если создать класс, инкапсулирующий двусвязный список, то его обработчик

    события Terminate сможет уничтожать список. Когда основная программа

    установит значение ссылки на список равным Nothing, список автоматически

    освободит занимаемую память.

    Программа DblLink работает с двусвязным списком. Она позволяет добавлять

    элементы до или после выбранного элемента, а также удалять выбранный

    элемент.

    =============39

    Потоки

    В некоторых приложениях бывает удобно обходить связный список не только в

    одном порядке. В разных частях приложения вам может потребоваться выводить

    список сотрудников по их фамилиям, заработной плате, идентификационному

    номеру системы социального страхования, или специальности.

    Обычный связный список позволяет просматривать элементы только в одном

    порядке. Используя указатель PrevCell, можно создать двусвязный список,

    который позволит перемещаться по списку вперед и назад. Этот подход можно

    развить и дальше, добавив больше указателей на структуру данных, позволяя

    выводить список в другом порядке.

    Набор ссылок, который задает какой-либо порядок просмотра, называется

    потоком (thread), а сам полученный список — многопоточным списком (threaded

    list). Не путайте эти потоки с потоками, которые предоставляет система

    Windows NT.

    Список может содержать любое количество потоков, хотя, начиная с какого-то

    момента, игра не стоит свеч. Применение потока, упорядочивающего список

    сотрудников по фамилии, будет обосновано, если ваше приложение часто

    использует этот порядок, в отличие от расположения по отчеству, которое

    вряд ли когда будет использоваться.

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

    поток, упорядочивающий сотрудников по полу, вряд ли целесообразен потому,

    что такое упорядочение легко получить и без него. Для того, чтобы составить

    список сотрудников по полу, достаточно просто обойти список по любому

    другому потоку, печатая фамилии женщин, а затем повторить обход еще раз,

    печатая фамилии мужчин. Для получения такого расположения достаточно всего

    двух проходов списка.

    Сравните этот случай с тем, когда вы хотите упорядочить список сотрудников

    по фамилии. Если список не включает поток фамилий, вам придется найти

    фамилию, которая будет первой в списке, затем следующую и т.д. Это процесс

    со сложностью порядка O(N2), который намного менее эффективен, чем

    сортировка по полу со сложностью порядка O(N).

    В общем случае, задание потока может быть целесообразно, если его

    необходимо часто использовать, и если при необходимости получить тот же

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

    заново.

    Программа Treads демонстрирует простой многопоточный список сотрудников.

    Заполните поля фамилии, специальности, пола и номера социального

    страхования для нового сотрудника. Затем нажмите на кнопку Add (Добавить),

    чтобы добавить сотрудника к списку.

    Программа содержит потоки, которые упорядочивают список по фамилии по

    алфавиту и в обратном порядке, по номеру социального страхования и

    специальности в прямом и обратном порядке. Вы можете использовать

    дополнительные кнопки для выбора потока, в порядке которого программа

    выводит список. На рис. 2.10 показано окно программы Threads со списком

    сотрудников, упорядоченным по фамилии.

    Класс ThreadedCell, используемый программой Threads, определяет следующие

    переменные:

    Public LastName As String

    Public FirstName As String

    Public SSN As String

    Public Sex As String

    Public JobClass As Integer

    Public NextName As TreadedCell ‘ По фамилии в прямом порядке.

    Public PrevName As TreadedCell ‘ По фамилии в обратном порядке.

    Public NextSSN As TreadedCell ‘ По номеру в прямом порядке.

    Public NextJobClass As TreadedCell ‘ По специальности в прямом

    порядке.

    Public PrevJobClass As TreadedCell ‘ По специальности в обратном

    порядке.

    Класс ThreadedList инкапсулирует многопоточный список. Когда программа

    вызывает метод AddItem, список обновляет свои потоки. Для каждого потока

    программа должна вставить элемент в правильном порядке. Например, для того,

    чтобы вставить запись с фамилией «Смит», программа обходит список,

    используя поток NextName, до тех пор, пока не найдет элемент с фамилией,

    которая должна следовать за «Смит». Затем она вставляет в поток NextName

    новую запись перед этим элементом.

    При определении местоположения новых записей в потоке важную роль играют

    сигнальные метки. Обработчик событий Class_Initialize класса ThreadedList

    создает сигнальные метки на вершине и в конце списка и инициализирует их

    указатели так, чтобы они указывали друг на друга. Затем значение метки в

    начале списка устанавливается таким образом, чтобы оно всегда находилось до

    любого значения реальных данных для всех потоков.

    Например, переменная LastName может содержать строковые значения. Пустая

    строка "" идет по алфавиту перед любыми действительными значениями строк,

    поэтому программа устанавливает значение сигнальной метки LastName в начале

    списка равным пустой строке.

    Таким же образом Class_Initialize устанавливает значение данных для метки в

    конце списка, превосходящее любые реальные значения во всех потоках.

    Поскольку "~" идет по алфавиту после всех видимых символов ASCII, программа

    устанавливает значение поля LastName для метки в конце списка равным "~".

    Присваивая полю LastName сигнальных меток значения "" и "~", программа

    избавляется от необходимости проверять особые случаи, когда нужно вставить

    новый элемент в начало или конец списка. Любые новые действительные

    значения будут находиться между значениями LastValue сигнальных меток,

    поэтому программа всегда сможет определить правильное положение для нового

    элемента, не заботясь о том, чтобы не зайти за концевую метку и не выйти за

    границы списка.

    @Рис. 2.10. Программа Threads

    =====41

    Следующий код показывает, как класс ThreadedList вставляет новый элемент в

    потоки NextName и PrevName. Так как эти потоки используют один и тот же

    ключ — фамилии, программа может обновлять их одновременно.

    Dim ptr As ThreadedCell

    Dim nxt As ThreadedCell

    Dim new_cell As New ThreadedCell

    Dim new_name As String

    Dim next_name As String

    ' Записать значения новой ячейки.

    With new_cell

    .LastName = LastName

    .FirstName = FirstName

    .SSN = SSN

    •Sex = Sex

    .JobClass = JobClass

    End With

    ' Определить место новой ячейки в потоке NextThread.

    new_name = LastName & ", " & FirstName

    Set ptr = m_TopSentinel

    Do

    Set nxt = ptr.NextName

    next_name = nxt.LastName & ", " & nxt.FirstName

    If next_name >= new_name Then Exit Do

    Set ptr = nxt

    Loop

    ' Вставить новую ячейку в потоки NextName и prevName.

    Set new_cell.NextName = nxt

    Set new_cell.PrevName = ptr

    Set ptr.NextName = new_cell

    Set nxt.PrevName = new_cell

    Чтобы такой подход работал, программа должна гарантировать, что значения

    новой ячейки лежат между значениями меток. Например, если пользователь

    введет в качестве фамилии "~~", цикл выйдет за метку конца списка, т.к.

    "~~" идет после "~". Затем программа аварийно завершит работу при попытке

    доступа к значению nxt.LastName, если nxt было установлено равным Nothing.

    ========42

    Другие связные структуры

    Используя указатели, можно построить множество других полезных

    разновидностей связных структур, таких как деревья, нерегулярные массивы,

    разреженные массивы, графы и сети. Ячейка может содержать любое число

    указателей на другие ячейки. Например, для создания двоичного дерева можно

    использовать ячейку, содержащую два указателя, один на левого потомка, и

    второй – на правого. Класс BinaryCell может состоять из следующих

    определений:

    Public LeftChild As BinaryCell

    Public RightChild As BinaryCell

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

    деревья обсуждаются более подробно.

    Ячейка может даже содержать коллекцию или связный список с указателями на

    другие ячейки. Это позволяет программе связать ячейку с любым числом других

    объектов. На рис. 2.12 приведены примеры других связных структур данных. Вы

    также встретите похожие структуры далее, в особенности в 12 главе.

    Псевдоуказатели

    При помощи ссылок в Visual Basic можно легко создавать связные структуры,

    такие как списки, деревья и сети, но ссылки требуют дополнительных

    ресурсов. Счетчики ссылок и проблемы с распределением памяти замедляют

    работу структур данных, построенных с использованием ссылок.

    Другой стратегией, которая часто обеспечивает лучшую производительность,

    является применение псевдоуказателей (fake pointers). При этом программа

    создает массив структур данных. Вместо использования ссылок для связывания

    структур, программа использует индексы массива. Нахождение элемента в

    массиве осуществляется в Visual Basic быстрее, чем выборка его по ссылке на

    объект. Это дает лучшую производительность при применении псевдоуказателей

    по сравнению с соответствующими методами ссылок на объекты.

    С другой стороны, применение псевдоуказателей не столь интуитивно, как

    применение ссылок. Это может усложнить разработку и отладку сложных

    алгоритмов, таких как алгоритмы сетей или сбалансированных деревьев.

    @Рис. 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

    Применение псевдоуказателей обычно обеспечивает лучшую производительность,

    но является более сложным. Поэтому имеет смысл сначала создать приложение,

    используя ссылки на объекты. Затем, если вы обнаружите, что программа

    значительную часть времени тратит на манипулирование ссылками, вы можете,

    если необходимо, преобразовать ее с использованием псевдоуказателей.

    Страницы: 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


    Приглашения

    09.12.2013 - 16.12.2013

    Международный конкурс хореографического искусства в рамках Международного фестиваля искусств «РОЖДЕСТВЕНСКАЯ АНДОРРА»

    09.12.2013 - 16.12.2013

    Международный конкурс хорового искусства в АНДОРРЕ «РОЖДЕСТВЕНСКАЯ АНДОРРА»




    Copyright © 2012 г.
    При использовании материалов - ссылка на сайт обязательна.