МЕНЮ


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

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


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

    Set cell2 = New EmpCell

    cell2.EmpName = "Кэтс”

    cell2.SSN = "123-45-6789"

    cell2.JobTitle = "Юрист"

    Set cell3 = New EmpCell

    cell3.EmpName = "Туле”

    cell3.SSN = "123-45-6789"

    cell3.JobTitle = "Менеджер"

    ‘ Соединить ячейки, образуя связный список.

    Set cell1.NextCell = cell2

    Set cell2.NextCell = cell3

    Set cell3.NextCell = Nothing

    ‘ Сохранить ссылку на вершину списка.

    Set top_cell = cell1

    ===============27

    На рис. 2.2 показано схематическое представление этого связного списка.

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

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

    которое обозначает конец списка. Имейте в виду, что top_cell, cell1 и

    cell2 – это не настоящие объекты, а только ссылки, которые указывают на

    них.

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

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

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

    вершину списка. В коде используется цикл Do для перемещения ptr по списку

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

    цикла, процедура печатает поле EmpName ячейки, на которую указывает ptr.

    Затем она увеличивает ptr, указывая на следующую ячейку в списке. В конце

    концов, ptr достигает конца списка и получает значение Nothing, и цикл Do

    останавливается.

    Dim ptr As EmpCell

    Set ptr = top_cell ‘ Начать с вершины списка.

    Do While Not (ptr Is Nothing)

    ‘ Вывести поле EmpName этой ячейки.

    Debug.Print ptr.Empname

    ‘ Перейти к следующей ячейке в списке.

    Set ptr = ptr.NextCell

    Loop

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

    Стивенс

    Кэтс

    Туле

    @Рис. 2.2. Связный список

    =======28

    Использование указателя на другой объект называется косвенной адресацией

    (indirection), поскольку вы используете указатель для косвенного

    манипулирования данными. Косвенная адресация может быть очень запутанной.

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

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

    сложных структурах данных, указатель может ссылаться на объект, содержащий

    другой указатель. Если есть несколько указателей и несколько уровней

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

    Для того, чтобы облегчить понимание, в изложении используются иллюстрации,

    такие как рис. 2.2,(для сетевой версии исключены, т.к. они многократно

    увеличивают размер загружаемого файла) чтобы помочь вам наглядно

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

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

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

    Простой связный список, показанный на рис. 2.2, обладает несколькими

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

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

    списка. Затем установим указатель top_cell на новую ячейку. Рис. 2.3

    соответствует этой операции. Код на языке Visual Basic для этой операции

    очень прост:

    Set new_cell.NextCell = top_cell

    Set top_cell = new_cell

    @Рис. 2.3. Добавление элемента в начало связного списка

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

    добавления нового элемента в начало списка, основанного на массиве, в

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

    чтобы освободить место для нового элемента. Эта операция со сложностью

    порядка O(N) может потребовать много времени, если список достаточно

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

    списка всего за пару шагов.

    ======29

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

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

    указывает переменная after_me. Установим значение NextCell новой ячейки

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

    новую ячейку. Эта операция показана на рис. 2.4. Код на Visual Basic снова

    очень прост:

    Set new_cell.NextCell = after_me.NextCell

    Set after_me.NextCell = new_cell

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

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

    его. Просто установите указатель top_cell на следующую ячейку в списке.

    Рис. 2.5 соответствует этой операции. Исходный код для этой операции еще

    проще, чем код для добавления элемента.

    Set top_cell = top_cell.NextCell

    Когда указатель top_cell перемещается на второй элемент в списке, в

    программе больше не останется переменных, указывающих на первый объект. В

    этом случае, счетчик ссылок на этот объект станет равен нулю, и система

    автоматически уничтожит его.

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

    удалить элемент, стоящий после ячейки after_me. Просто установите указатель

    NextCell этой ячейки на следующую ячейку. Эта операция показана на рис.

    2.6. Код на Visual Basic прост и понятен:

    after_me.NextCell = after_me.NextCell.NextCell

    @Рис. 2.4. Добавление элемента в середину связного списка

    =======30

    @Рис. 2.5. Удаление элемента из начала связного списка

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

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

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

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

    и соответственно быть более сложными. Присутствие чрезмерного количества

    «мусора» также замедляет работу процедуры, и, в конце концов, придется

    проводить чистку памяти.

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

    промежутков. Процедуры, которые обрабатывают список, все так же обходят

    список с начала до конца, и не нуждаются в модификации.

    Уничтожение связного списка

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

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

    На самом деле процесс гораздо проще: только top_cell принимает значение

    Nothing.

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

    ссылок для первой ячейки становится равным нулю, и Visual Basic уничтожает

    эту ячейку.

    Во время уничтожения ячейки, система определяет, что в поле NextCell этой

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

    уничтожается, то число ссылок на второй объект уменьшается. При этом

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

    система уничтожает и его.

    Во время уничтожения второго объекта, система уменьшает число ссылок на

    третий объект, и так далее до тех пор, пока все объекты в списке не будут

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

    уничтожить и весь список при помощи единственного оператора Set

    top_cell = Nothing.

    @Рис. 2.6. Удаление элемента из середины связного списка

    ========31

    Сигнальные метки

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

    используются различные процедуры. Можно свести оба этих случая к одному и

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

    (sentinel) в самом начале списка. Сигнальную метку нельзя удалить. Она не

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

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

    начало списка, можно помещать элемент после метки. Таким же образом, вместо

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

    элемент, следующий за меткой.

    Использование сигнальных меток пока не вносит особых различий. Сигнальные

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

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

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

    согласованными и более простыми для понимания.

    В табл. 2.1 сравнивается сложность выполнения некоторых типичных операций с

    использованием списков на основе массивов со «сборкой мусора» или связных

    списков.

    Списки на основе массивов имеют одно преимущество: они используют меньше

    памяти. Для связных списков необходимо добавить поле NextCell к каждому

    элементу данных. Каждая ссылка на объект занимает четыре дополнительных

    байта памяти. Для очень больших массивов это может потребовать больших

    затрат памяти.

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

    меткой. Введите значение в текстовое поле ввода, и нажмите на элемент в

    списке или на метку. Затем нажмите на кнопку Add After (Добавить после), и

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

    списка, нажмите на элемент и затем на кнопку Remove After (Удалить после).

    @Таблица 2.1. Сравнение списков на основе массивов и связных списков

    =========32

    Инкапсуляция связных списков

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

    показывает, как программа удаляет элемент из списка. Когда подпрограмма

    начинает работу, глобальная переменная SelectedIndex дает положение

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

    содержит ссылку на сигнальную метку списка.

    Private Sub CmdRemoveAfter_Click()

    Dim ptr As ListCell

    Dim position As Integer

    If SelectedIndex < 0 Then Exit Sub

    ‘ Найти элемент.

    Set ptr = Sentinel

    position = SelectedIndex

    Do While position > 0

    position = position - 1

    Set ptr = ptr.nextCell

    Loop

    ‘ Удалить следуюший элемент.

    Set ptr.NextCell = ptr.NextCell.NextCell

    NumItems = NumItems - 1

    SelectItem SelectedIndex ‘ Снова выбрать элемент.

    DisplayList

    NewItem.SetFocus

    End Sub

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

    функции в классе. Это реализовано в программе LnkList2 . Она аналогична

    программе LnkList1, но использует для управления списком класс LinkedList.

    Класс LinekedList управляет внутренней организацией связного списка. В нем

    находятся процедуры для добавления и удаления элементов, возвращения

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

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

    массивом.

    Это намного упрощает основную программу. Например, следующий код

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

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

    Остальные отображают новый список. Сравните этот код с предыдущей

    процедурой:

    Private sub CmdRemoveAfter_Click()

    Llist.RemoveAfter SelectedIndex

    SelectedItem SelectedList ‘ Снова выбрать элемент.

    DisplayList

    NewItem.SetFocus

    CmdClearList.Enabled

    End Sub

    =====33

    Доступ к ячейкам

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

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

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

    положению:

    Function Item(ByVal position As Long) As Variant

    Dim ptr As ListCell

    If position < 1 Or position > m_NumItems Then

    ‘ Выход за границы. Вернуть NULL.

    Item = Null

    Exit Function

    End If

    ‘ Найти элемент.

    Set ptr = m_Sentinel

    Do While position > 0

    position = position - 1

    Set ptr = ptr.NextCell

    Loop

    Item = ptr.Value

    End Function

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

    структуры списка. Например, предположим, что программе требуется

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

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

    коде:

    Dim i As Integer

    For i = 1 To LList.NumItems

    ‘ Выполнить какие-либо действия с LList.Item(i).

    :

    Next i

    При каждом вызове процедуры Item, она просматривает список в поиске

    следующего элемента. Чтобы найти элемент I, программа должна пропустить I-1

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

    пропустит 0+1+2+3+…+N-1 =N*(N-1)/2 элемента. При больших N программа

    потеряет много времени на пропуск элементов.

    Класс LinkedList может ускорить эту операцию, используя другой метод

    доступа. Можно использовать частную переменную m_CurrentCell для

    отслеживания текущей позиции в списке. Для возвращения значения текущего

    положения используется подпрограмма CurrentItem. Процедуры MoveFirst,

    MoveNext и EndOfList позволяют основной программе управлять текущей

    позицией в списке.

    =======34

    Например, следующий код содержит подпрограмму MoveNext:

    Public Sub MoveNext()

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

    If Not (m_CurrentCell Is Nothing) Then _

    Set m_CurrentCell = m_CurrentCell.NextCell

    End Sub

    При помощи этих процедур, основная программа может обратиться ко всем

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

    чем предыдущая, но она намного эффективнее. Вместо того чтобы пропускать

    N*(N-1)/2 элементов и опрашивать по очереди все N элементов списка, она не

    пропускает ни одного. Если список состоит из 1000 элементов, это экономит

    почти полмиллиона шагов.

    LList.MoveFirst

    Do While Not LList.EndOfList

    ‘ Выполнить какие-либо действия над элементом LList.Item(i).

    :

    LList.MoveNext

    Loop

    Программа LnkList3 использует эти новые методы для управления связным

    списком. Она аналогична программе LnkList2, но более эффективно обращается

    к элементам. Для небольших списков, используемых в программе, эта разница

    незаметна. Для программы, которая обращается ко всем элементам большого

    списка, эта версия класса LinkedList более эффективна.

    Разновидности связных списков

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

    встречаться с ними на протяжении всего материала. В следующих разделах

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

    Циклические связные списки

    Вместо того, чтобы устанавливать указатель NextCell равным Nothing, можно

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

    (circular list), как показано на рис. 2.7.

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

    цикле. При каждом шаге цикла, программа просто перемещает указатель на

    следующую ячейку в списке. Допустим, имеется циклический список элементов,

    содержащий названия дней недели. Тогда программа могла бы перечислять дни

    месяца, используя следующий код:

    ===========35

    @Рис. 2.7. Циклический связный список

    ‘ Здесь находится код для создания и настройки списка и т.д.

    :

    ‘ Напечатать календарь на месяц.

    ‘ first_day — это индекс структуры, содержащей день недели для

    ‘ первого дня месяца. Например, месяц может начинаться

    ‘ в понедельник.

    ‘ num_days — число дней в месяце.

    Private Sub ListMonth(first_day As Integer, num_days As Integer)

    Dim ptr As ListCell

    Dim i As Integer

    Set ptr = top_cell

    For i = 1 to num_days

    Print Format$(i) & ": " & ptr.Value

    Set ptr = ptr.NextCell

    Next I

    End Sub

    Циклические списки также позволяют достичь любой точки в списке, начав с

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

    Программа может обращаться со всеми элементами списка почти одинаковым

    образом:

    Private Sub PrintList(start_cell As Integer)

    Dim ptr As Integer

    Set ptr = start_cell

    Do

    Print ptr.Value

    Set ptr = ptr.NextCell

    Loop While Not (ptr Is start_cell)

    End Sub

    ========36

    Проблема циклических ссылок

    Уничтожение циклического списка требует немного больше внимания, чем

    удаление обычного списка. Если вы просто установите значение переменной

    top_cell равным Nothing, то программа не сможет больше обратиться к списку.

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

    будет уничтожена. На каждый элемент списка указывает какой-либо другой

    элемент, поэтому ни один из них не будет уничтожен.

    Это проблема циклических ссылок (circular referencing problem). Так как

    ячейки указывают на другие ячейки, ни одна из них не будет уничтожена.

    Программа не может получить доступ ни к одной из них, поэтому занимаемая

    ими память будет расходоваться напрасно до завершения работы программы.

    Проблема циклических ссылок может встретиться не только в этом случае.

    Многие сети содержат циклические ссылки — даже одиночная ячейка, поле

    NextCell которой указывает на саму эту ячейку, может вызвать эту проблему.

    Решение ее состоит в том, чтобы разбить цепь ссылок. Например, вы можете

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

    связного списка:

    Set top_cell.NextCell = Nothing

    Set top_cell = Nothing

    Первая строка разбивает цикл ссылок. В этот момент на вторую ячейку списка

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

    ячейки до нуля и уничтожает ее. Это уменьшает счетчик ссылок на третий

    элемент до нуля, и соответственно, он также уничтожается. Этот процесс

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

    кроме первого. Установка значения top_cell элемента в Nothing уменьшает его

    счетчик ссылок до нуля, и последняя ячейка также уничтожается.

    Двусвязные списки

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

    операций определялось в терминах выполнения чего-либо после определенной

    Страницы: 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 г.
    При использовании материалов - ссылка на сайт обязательна.