Новости/News | | Туториалы/Tutorials | | Форум/Forum | | ЧаВо/FAQ | | Файлы/Downloads | | Ссылки/Links | | Авторы/About |

Связные списки

Содержание

Вступление

Возможно многие из вас встречались с связными списками в программировании, в UnrealScript также возможна организация списковых структур. Одной из причин использования списков является отсутствие поддержки динамических массивов в ускрипте (однако возможно появление таких структур, см. интервью с Tim Sweeney). В настоящий момент списки довольно интенсивно используются в скрипте (инвентори, список мутаторов и т.д.)
Подразумевается что вы имеете неплохое знание ускрипта.

Список и его реализация

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

Список представляет собой цепочку элементов, каждый из которых имеет указатель на следующий элемент. Дополнительно мы имеем отдельный указатель на начальный элемент списка, непосредственные данные хранятся в элементах списка. Последний элемент указывает на "пустой" объект (None). Преимущества такой организации - нет ограничения на количество элементов, легкость добавления/удаления элементов в списке. Основной недостаток - невозможность непосредственного обращения к любому элементу (мы же "знаем" только начало списка). Например чтобы добраться до последнего элемента списка мы должны пройтись по всему списку с самого начала.

Итак, обычный список состоит из следующих компонент:

  1. Указатель на начало списка (отдельная переменная)
  2. Элементы списка, каждый элемент содержит данные и указатель на следующий элемент

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

// Отдельный элемент списка, разумеется необязательно наследовать
// от класса Object, подбирайте по вашему усмотрению
class ListElement extends Object;

var string SomeData; // здесь храним какие-либо данные
var ListElement Next; // указатель на следующий элемент списка

Указатель на начало списка вы объявляете в классе в котором ваш список и используется.

class SomeYourClass extends Actor;

var ListElement TopElement; // указатель на начало списка

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

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

Просмотр элементов в списке

Наиболее естественный способ - при помощи циклов (for,while,do-until) просматривать все элементы списка с самого начала. Пример с while был рассмотрен выше, наиболее часто используется for:

local ListElement TempElement;

For (TempElement=ListElement; TempElement!=none; TempElement=TempElement.Next)
  // производим необходимые действия

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

Разумеется "просто так" удалять элементы из списка нельзя - нарушатся связи и удаление элемента "разорвет" список. Намного проще - перестраивать связи, как это выглядит примерно показано на схеме (удаляемый элемент Element2):

Схема перестройки связей

Правда есть один недостаток - в памяти "висит" ненужный элемент, это нетрудно исправить для акторов - при помощи метода Destroy, на Object классы это не распространяется, т.к. их нельзя удалять вручную. Если элементы вашего списка - акторы, можно еще дополнительно задействовать метод Destroyed() который вызывается для всех акторов подлежащих удалению.

Вот пример кода осуществляющий перестройку связей без удаления самих элементов:

// В классе который использует список
// Element - удаляемый элемент

Function RemoveElement(ListElement Element) {
  Local ListElement List;

  // Если удаляется первый элемент то меняем значение
  // указателя на верхушку списка
  If (Element==TopElement)
    TopElement=TopElement.Next;
  Else
    // Иначе ищем удаляемый элемент в списке и меняем связи
    // по вышеприведенной схеме
    For (List=TopElement;List!=none;List=List.Next)
      If (List.Next==Element) {
        List.Next=Element.Next;
        Break;
      }
}

"Продвинутые" списки

Разумеется вы можете строить более сложные типы списков. Например ввести дополнительный указатель не только на следующий элемент, но и предыдущий. Тогда при просмотре списка и поиске нужного элемента будет тратиться меньше времени. Один из примеров такого рода списков - реализация истории сообщений транслятора в Operation: Na Pali. Здесь можно взять "базовую" реализацию такого рода списков, вы можете использовать в качестве основы в своем коде.

Существующие виды списков в UT

Рассмотрим уже имеющиеся списки в Unreal Tournament.

Автор

Автор: Shadow
Mail: shadow_m777@mail.ru

Большая часть материала основана на туториале Linked Lists Part 1 (вся глава "Существующие виды списков в UT") c сайта CHiMERiC.
Автор: UsAaR33
Mail: usaar33@yahoo.com
Web: www.usaar33.com

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