5
В этой главе я расскажу, как создать и использовать другие методы
для хранения и управления данными, такие,
как структуры, массивы и связанные списки. Данные, такие как структуры
необходимы для программирования игр и приложений,
поскольку они позволяют получить более легкий и быстрый доступ к
нескольким значениям связанных и не связанных данных.
Как всегда, даются разъяснения и несколько примеров.
Структуры:
Ранее, во 2 главе, я представил вам встроенные типы данных, Byte,
Character, Word, Long, Quad, Float,
Double и String. Используя в структуре слова c
ключами(.s,.l,.b,.w,.c,.q), вы можете определить свой собственный
структурированный тип данных, а затем присвоить этот тип
переменной(ым). Создание собственных структурированных
переменных удобно, особенно если вам понадобятся много общих имен
переменных в рамках одной структуры.
Непонятно? Тогда давайте посмотрим на примере структуры, которая
содержит несколько полей:
Structure PERSONALDETAILS
FirstName.s
LastName.s
Home.s
EndStructure
Me.PERSONALDETAILS
Me\FirstName = "Gary"
Me\LastName = "Willoughby"
Me\Home = "A House"
Debug "First Name: " + Me\FirstName
Debug "Last Name: " + Me\LastName
Debug "Home: " + Me\Home
Структура 'PERSONALDETAILS' создается с использованием
ключевого слова Structure.
Далее идут компоненты структуры
которые определяются точно так же, как обычные переменные. Ключевое
слово EndStructure используется
для определения
конца структуры. После того как структура объявлена, она готова к
использованию. Мы придали этой структуре тип так же, как мы
назначаем любой тип переменной, пример:
Me.PERSONALDETAILS
Здесь имя переменной 'Me' и его тип 'PERSONALDETAILS'.
Чтобы присвоить значения отдельным
переменным (иногда называемые полями) в рамках новой 'Me'
структурированной переменной, мы используем символ '\'. Если
вы посмотрите на пример выше, то заметите,
что ‘\’, символ также используется, чтобы восстановить
данные из индивидуальных полей
также, как здесь:
Father.PERSONALDETAILS
Father\FirstName = "Peter"
Debug Father\FirstName
Здесь, в этом маленьком
примере, мы создали новую структурированную переменную
"Father"
с структурированным типом "PERSONALDETAILS ". Мы придаем
значение 'Peter' для Father\FirstName.
Затем мы вывели это значение в окне отладки. Конечно по этим
примерам вы возможно не увидели пользы от структур, но они невероятно полезны.
Рассмотрение памяти
Размер памяти структурированной переменной зависит от полевой
переменной, используемой в первоначальном
определении структуры. В структуре "PERSONALDETAILS"
определены три переменные с
типом String, каждая из которых имеет размер 4 байта (см.
Рис.3 ранее в главе 2 для размеров, типов String).
Таким образом, вновь заявленная переменная 'Me' занимает 12
байт (3 х 4 байта) в памяти. Мы можем проверить это,
с помощью функции 'SizeOf ()'.
Structure PERSONALDETAILS
FirstName.s
LastName.s
Home.s
EndStructure
Debug SizeOf(PERSONALDETAILS)
Функция 'sizeof ()' возвращает значение '12', которое показывает, сколько байт использует структура в памяти.
Функция
‘SizeOf()’
Эта команда возвращает размер любой структуры или переменной,
определяемой в байтах. Она не работает с массивами,
связанными списками или интерфейсом. Эта команда имеет неоценимое
значение для программирования в Windows, поскольку
некоторые Win32 API функции требуют размера конкретной структуры или
переменной в качестве параметра. Больше о Win32 API
мы узнаем позже в главе 13.
Дополнение полей из другой структуры
Структуры можно дополнить полями из другой структуры с помощью параметра ‘Extends’
Structure PERSONALDETAILS
FirstName.s
LastName.s
Home.s
EndStructure
Structure FULLDETAILS Extends
PERSONALDETAILS
Address.s
Country.s
ZipCode.s
EndStructure
User.FULLDETAILS
User\FirstName = "John"
User\LastName = "Smith"
User\Home = "A House"
User\Address = "A Street"
User\Country = "UK"
User\ZipCode = "12345"
Debug "Users First Name: " +
User\FirstName
Debug "Users Last Name: " + User\LastName
Debug "Users Home: " + User\Home
Debug "Users Address: " + User\Address
Debug "Users Country: " + User\Country
Debug "Users Zip Code: " + User\ZipCode
В этом примере структуру
'FULLDETAILS' расширяет структура 'PERSONALDETAILS'
и вновь получаемая структура дополняется данными из структуры 'PERSONALDETAILS' , причем
так, что взятые данные
появляются первыми в нашей новой структуре. Мы присвоили этой
новосозданной структуре переменную 'User',
ну и присвоили значения во всех ее сферах. Затем эти данные
проверили в окне отладки.
Структуры Union (объединенные)
Структуры Union
- способ сохранить память, вынуждая группы переменных совместно
использовать в пределах структуры
тот же самый адрес памяти. Возможно я залез немного вперед, но поверьте
мне пришлось это сделать для законченности.
Вы можете просмотреть Главу 13 (Pointers), чтобы понять лучше, как это
работает. Вот простой пример:
Structure UNIONSTRUCTURE
StructureUnion
One.l
Two.l
Three.l
EndStructureUnion
EndStructure
Debug SizeOf(UNIONSTRUCTURE)
UnionVariable.UNIONSTRUCTURE
UnionVariable\One = 123
Debug UnionVariable\One
UnionVariable\Three = 456
Debug UnionVariable\One
После объявления 'UNIONSTRUCTURE'
мы использовали StructureUnion и EndStructureUnion
для инкапсуляции
переменных, которым мы хотим использовать одну выделенную область
памяти.
Когда мы запускаем эту небольшую программу,первое что появляется в окне
отладки это '4 '(байта), поскольку
структура имеет размер одной переменной из-за того, что все переменные
в такой структуре задействуют только
одно место в памяти.
Далее в программе мы присвоиваем UnionVariable тип UNIONSTRUCTURE
и назначаем значение '123' для UnionVariable\One,
затем считываем его в окне отладки. После мы присвоиваем новое значение
'456' для UnionVariable\Three, и снова считываем
старую переменную UnionVariable\One. Но так как используется
одна и та же область памяти для всех переменных в структуре
то переменной UnionVariable\One присваивается новое значение
'456' которое как мы помним, мы присвоили 'UnionVariable\Three'.
Структуры могут содержать так называемые статические массивы, но мне
нужно объяснить массивы, прежде чем мы
может применять эти знания для структур. Массивы и статические массивы
объясняются в полном объеме в следующем разделе.
Массивы:
В PureBasic, массивы могут вмещать определяемое пользователем кол-во
переменных, одинакового типа данных. Каждая переменная
в массиве имеет свой индекс, который лежит в последовательном диапазоне
целых чисел. Массивы могут также быть определены для структурированных
переменных. Этот раздел научит вас всему, что нужно знать о массивах в
PureBasic.
DIM
Массивы создаются с помощью команды
DIM:
Dim LongArray.l(2)
Позвольте мне объяснить эту строку кода более понятно. Во-первых мы
используем команду Dim , чтобы сообщить компилятору, что
мы собираемся определить массив. Затем мы даем имя массиву. В данном
случае, я назвал его LongArray. После названия, мы аналогично
переменным,
присваиваем тип массиву с помощью суффикса '. l'. Итак, массив
имеет тип
Long.
После того, как определен тип, нам надо определить, сколько индексов
будет содержать массив.Для определения индекса используются целые числа
в круглых скобках. В приведенном выше примере мы использовали (2). Это
означает,
что массив сможет вместить три переменных. Почему три, а не две?
Потому, что отсчет в массивах всегда начинается с нуля, а цифра (2)
показывает последний индекс массива.После того как массив был
создан,
все его переменные будут иметь тип Long. Это простой массив. Чаще такой массив
называют одномерным. Давайте посмотрим на наглядном примере в котором
мы определим массив и присвоим значения всем его индексам:
Dim LongArray.l(2)
LongArray(0) = 10
LongArray(1) = 25
LongArray(2) = 30
Debug LongArray(0) + LongArray(1)
Debug LongArray(1) * LongArray(2)
Debug LongArray(2) - LongArray(0)
После того как мы присвоили значения переменным массива, мы произвели с ними математические операции и вывели результат в окно отладки. Например, первым результатом будет сложение '10 + 25 ',поскольку мы сложили индексы '0 'и '1'. Вторым результатом умножение '25' * '30 ', третьим '30'-'10'. Индексы могут задаваться не только с помощью выражений, но и с помощью переменных:
LastIndex.l = 2
FirstIndex.l = 0
Dim StringArray.s(LastIndex)
StringArray(FirstIndex) = "One is one and all alone"
StringArray(FirstIndex + 1) = "Two, two, the lily-white
boys"
StringArray(FirstIndex + 2) = "Three, three, the rivals"
Debug StringArray(FirstIndex)
Debug StringArray(FirstIndex + 1)
Debug StringArray(FirstIndex + 2)
Здесь мы определили массив с тремя индексами, каждый из которых содержит строковую переменную(обратите внимание на суффикс .s). С помощью переменной LastIndex мы сумели задать три индекса. Затем мы использовали переменную FirstIndex чтобы заполнить массив тремя переменными. Далее попросту считали данные из массива в отладочное окно. См. таблицу ниже для большего понимания соответствия индексов и значений:
Индекс | Значение |
0 | One is one and all alone |
1 | Two, two, the lily-white boys |
2 | Three, three, the rivals |
Поскольку массивы аккуратно отсортированы в индексы, это дает
возможность для перебора их с помощью циклов, очень быстро. Вот пример
массива с 1000 индексами.
Сначала с помощью первого цикла мы заполняем массив, а вторым циклом
считываем данные из массива в окно отладки.
Dim TestArray.l(999)
For x = 0 To 999
TestArray(x) = x
Next x
For x = 0 To 999
Debug TestArray(x)
Next x
Запустите код и посмотрите в окно отладки. Как вы можете видеть, с помощью циклов легко и быстро заполнить массив, а потом так же быстро считать из массива.
Многомерные массивы
Лучший способ описать многомерные массивы,это создать таблицу.Чтобы
понять как размещаются данные, мы
просто укажем число столбцов и строк, которые имеет массив.(Но это чуть
ниже). А сейчас посмотрим пример
где создадим массив,так называемый "Animals",который состоит из
трех индексов,каждый из которых содержит
еще три индекса.
Dim Animals.s(2, 2)
Animals(0, 0) = "Sheep"
Animals(0, 1) = "4 Legs"
Animals(0, 2) = "Baaa"
Animals(1, 0) = "Cat"
Animals(1, 1) = "4 Legs"
Animals(1, 2) = "Meow"
Animals(2, 0) = "Parrot"
Animals(2, 1) = "2 Legs"
Animals(2, 2) = "Screech"
Debug Animals(0, 0) + " has " + Animals(0, 1) + " And says " +
Animals(0, 2)
Debug Animals(1, 0) + " has " + Animals(1, 1) + " And says " +
Animals(1, 2)
Debug Animals(2, 0) + " has " + Animals(2, 1) + " And says " +
Animals(2, 2)
И так давайте посмотрим в обещанную таблицу, в которой все наглядно видно и понятно:
ИНДЕКС | 0 | 1 | 2 |
0 | Sheep | 4 Legs | Baaa |
1 | Cat | 4 Legs | Meow |
2 | Parrot | 2 Legs | Screech |
Из таблицы видно, как располагаются данные в массиве.
Допустим мы хотим сменить данные в нулевой строке. Тогда так:
Animals(0, 0) = "Tripod"
Animals(0, 1) = "3 Legs"
Animals(0, 2) = "Oo-la"
В итоге будет следующее:
ИНДЕКС | 0 | 1 | 2 |
0 | Tripod | 3 Legs | Oo-la |
1 | Cat | 4 Legs | Meow |
2 | Parrot | 2 Legs | Screech |
Еще один способ объяснить многомерные
массивы в том, что их принцип
массив в массиве. Вспомним, что
в каждом массиве индекса содержится другой массив, и вы получите идею
многомерных массивов.
В следующем примере показано , как определить один, два, три, четыре
и пятьмерных массивов:
Dim Animals.s(5)
Dim Animals.s(5, 4)
Dim Animals.s(2, 5, 3)
Dim Animals.s(1, 5, 4, 5)
Dim Animals.s(2, 3, 6, 2, 3)
После двумерных массивов, трехмерные и т д, кажутся сложными, но
если вы вспомните, массив
в массиве, то становится более менее понятно. Хотя максимальный
ряд аспектов, который
может быть отнесен к элементам массива двести пятьдесят пять (255),
использование массивов
более двух или более трех измерениях необычное в повседневной
практике программирования.
Структурированный тип массивов
До сих пор мы видели, как применять различные массивы,
используя только стандартные средства, но у нас есть
возможность применять массивы, используя структуру. Давайте рассмотрим
простой пример использования одномерного массива:
Structure FISH
Kind.s
Weight.s
Color.s
EndStructure
Dim FishInTank.FISH(2)
FishInTank(0)\Kind = "Clown Fish"
FishInTank(0)\Weight = "4 oz."
FishInTank(0)\Color = "Red, White and Black"
FishInTank(1)\Kind = "Box Fish"
FishInTank(1)\Weight = "1 oz."
FishInTank(1)\Color = "Yellow"
FishInTank(2)\Kind = "Sea Horse"
FishInTank(2)\Weight = "2 oz."
FishInTank(2)\Color = "Green"
Debug FishInTank(0)\Kind+" "+FishInTank(0)\Weight+"
"+FishInTank(0)\Color
Debug FishInTank(1)\Kind+" "+FishInTank(1)\Weight+"
"+FishInTank(1)\Color
Debug FishInTank(2)\Kind+" "+FishInTank(2)\Weight+"
"+FishInTank(2)\Color
После того как мы определили структуру FISH,
мы определили массив, используя команду DIM,
а суффикс FISH - тип массива.
Все так же, как мы использовали .S (string) в массиве Animals.
Кроме того мы использовали '2' в качестве последнего индекса в этом
массиве.
Для присвоения значений полей каждому индексу массива, надо просто
объединить синтаксис задания массивов и структур:
FishInTank(0)\Kind = "Clown Fish"
Давайте попробуем разбить эту часть кода на куски для большего
понимания. Во-первых, имя массива, в данном случае это
"FishInTank. Затем идет текущий индекс, содержащийся в скобках, в
данном случае индекс '0 '. Далее мы используем
символ '\' для доступа к области, называемой "KIND"
в пределах FISH структуры, которая была
возложена на массив
FishInTank. Затем мы используем оператор '=', чтобы присвоить строковое
значение. Для получения значения, которое мы только что назначили,
мы просто используем точно такой же синтаксис, как при назначении. В
данном случае мы выводим значение в окно отладки:
Debug FishInTank(0)\Kind
Если нам необходимо получить и другие значения индексов массива, мы делаем это так:
Debug FishInTank(0)\Kind
Debug FishInTank(1)\Kind
Debug FishInTank(2)\Kind
Это был список полей Kind всех индексов массива FishInTank. Чтобы
получить значение из других областей,
мы просто используем их имена:
Debug FishInTank(1)\Kind
Debug FishInTank(1)\Weight
Debug FishInTank(1)\Color
Здесь мы получаем все поля, одного из индексов массива '1 '. Чтобы было более понятно давайте опять создадим графическую таблицу
ИНДЕКС | Структура FISH |
0 | Kind: Clown Fish Weight: 4 oz. Colour: Red, White and Black |
1 | Kind: Box Fish Weight: 1 oz. Colour: Yellow |
2 | Kind: Sea Horse Weight: 2 oz. Colour: Green |
Как и в случае с одномерными массивами, вы можете указать многомерные массивы с помощью структуры. Вы получите доступ к полям структуры в рамках каждого из индексов внутри многомерных массивов. Чтобы определить многомерный структурированный тип массива, делайте это в точности так же, только дополнив индексы.
Structure FISH
Kind.s
Weight.s
Color.s
EndStructure
Dim FishInTank.FISH(2, 2)
........
Я не буду набирать код массива, думаю и так все понятно, что следует вместо многоточия. С другой стороны мы создадим таблицу многомерного массива.
ИНДЕКС | 0 | 1 | 2 |
0 | Kind: Clown Fish Weight: 4 oz. Colour: Red, White and Black |
Kind: Box Fish Weight: 1 oz. Colour: Yellow |
Kind: Sea Horse Weight: 2 oz. Colour: Green |
1 | Kind: Parrot Fish Weight: 5 oz. Colour: Red |
Kind: Angel Fish Weight: 4 oz. Colour: Orange |
Kind: Shrimp Weight: 1 oz. Colour: Pink |
2 | Kind: Gold Fish Weight: 2 oz. Colour: Orange |
Kind: Lion Fish Weight: 8 oz. Colour: Black and White |
Kind: Shark Weight: 1 lb. Colour: Grey |
Для получения значения из этого вида массива мы должны указать в скобках два индекса, то есть так:
Debug FishInTank(1, 1)\Kind
Если мы хотим изменить данные в массиве, то это можно сделать так:
FishInTank(1, 1)\Kind = “Devil
Fish”
FishInTank(1, 1)\Weight = “6 oz.”
FishInTank(1, 1)\Color = “Dark Red”
Мы изменили все поля структура FISH, которые расположены в средней части массива под индексом '1, 1 '. Смотрим ниже:
ИНДЕКС | 0 | 1 | 2 |
0 | Kind: Clown Fish Weight: 4 oz. Colour: Red, White and Black |
Kind: Box Fish Weight: 1 oz. Colour: Yellow |
Kind: Sea Horse Weight: 2 oz. Colour: Green |
1 | Kind: Parrot Fish Weight: 5 oz. Colour: Red |
Kind: Devil Fish Weight: 6 oz. Colour: Dark Red |
Kind: Shrimp Weight: 1 oz. Colour: Pink |
2 | Kind: Gold Fish Weight: 2 oz. Colour: Orange |
Kind: Lion Fish Weight: 8 oz. Colour: Black and White |
Kind: Shark Weight: 1 lb. Colour: Grey |
Вы, вероятно, используете только одномерные структурированные
массивы в ваших программах на данный момент, но
знайте, что многомерные массивы структурированного типа дадут вам
хорошее представление о более
расширенном коде.
Переопределение созданного массива
Стандартные массивы в PureBasic не статичны, то есть они могут быть
переопределены двумя разными способами. Первый способ заключается в
использовании команды Dim которая
переопределяет массив, но в процессе уничтожает все предыдущие данные,
имеющиеся в нем. Второй способ заключается в использовании команды ReDim,
которая
переопределяет массив, но сохраняет предыдущие данные нетронутыми.
Давайте посмотрим на переопределение массива с помощью команды
Dim:
Dim Dogs.s(2)
Dogs(0) = "Jack Russell"
Dogs(1) = "Alaskan Husky"
Dogs(2) = "Border Collie"
Debug Dogs(0)
Debug Dogs(1)
Debug Dogs(2)
Dim Dogs.s(2)
Debug Dogs(0)
Debug Dogs(1)
Debug Dogs(2)
Здесь после создания и заполнения массива, мы переопределив его попросту стираем все данные в нем. Это может быть очень полезно. К примеру надо очистить лишнюю используемую память после массива.Но знайте, что переопределяя массив, надо применять тот же тип, иначе будет ошибка. А теперь давайте воспользуемся командой ReDim и переопределим массив, дополнив его, причем старые данные сохранятся:
Dim Dogs.s(2)
Dogs(0) = "Jack Russell"
Dogs(1) = "Alaskan Husky"
Dogs(2) = "Border Collie"
For x.l = 0 To 2
Debug Dogs(x)
Next x
Debug ""
ReDim Dogs.s(4)
Dogs(3) = "Yorkshire Terrier"
Dogs(4) = "Greyhound"
For x.l = 0 To 4
Debug Dogs(x)
Next x
В примере выше мы дополнили массив двумя ячейками, в результате их стало пять.
Правила пользования массивов
Хотя массивы являются очень гибкими, существует несколько правил,
которые должны учитываться при их использовании.
Правила должны быть соблюдены при использовании массивов в своих
программах.
1). Если массив повторно определяется с помощью команды
Dim, массив теряет свои
предыдущие данные.
2). Если массив повторно определяется с помощью команды ReDim,
то предыдущие данные сохраняются.
3). Массивы могут быть сделаны только из одного типа переменной
(структурированного или стандартного типа переменной).
4). Массивы могут быть глобальными(Global), защищенной(Protected),
статические(Static) и общие(Shared) (. См.
главу 6 ).
5). Размер массива ограничен только оперативной памятью текущей машины.
6). Многомерные массивы могут иметь размер 255.
7). Массивы можно динамически определить с помощью переменной или
выражения указывая размер.
8). При определении размера , вы определяете последний номер, а отсчет
начинается с нуля.
9). Индексы могут быть различных размеров в многомерных массивах.
Статические массивы в структурах
Статические массивы в структурах немного отличаются от обычных
массивов, которые были
описаны ранее. Статические массивы в самой своей природе являются
статичными и поэтому не могут быть изменены,
после того, как они определены. Эти типы массивов существуют только в
рамках структуры.
Статические массивы также имеют различный набор правил, которые учитывается при их использовании:
1). Как только статический массив определен, его внутренняя
структура не может быть изменена.
2). Статические массивы (как структуры) не могут быть переопределены.
3). Они могут быть сделаны только из одного типа переменной
(структурированного или стандартного типа переменной).
4). Размер массива ограничен только установленной оперативной памятью
текущей машины.
5). У статических массивов может только быть одна размерность.
6). Они могут быть динамически определены, используя переменную или
выражение, в которой задается размер
7). При определении размера , вы определите кол-во индексов и оно
показывает реальный размер массива.
8). Статические массивы могут быть доступны только через структуру
переменных, в которых они определены.
После того как я дал вам основные правила, позвольте мне привести вам пример того, как они используются:
Structure FAMILY
Father.s
Mother.s
Children.s[2]
Surname.s
EndStructure
Family.FAMILY
Family\Father = "Peter"
Family\Mother = "Sarah"
Family\Children[0] = "John"
Family\Children[1] = "Jane"
Family\Surname = "Smith"
Debug "Family Members:"
Debug Family\Father + " " + Family\Surname
Debug Family\Mother + " " + Family\Surname
Debug Family\Children[0] + " " + Family\Surname
Debug Family\Children[1] + " " + Family\Surname
В этом примере, структура "FAMILY"
имеет поле с названием "Children",
которое представляет собой статический строковой массив.
Когда мы определили этот массив, мы использовали цифру '2 '. Это
означает, что в массиве два индекса.
Это не похоже на стандартные массивы, в котором вы определяете
последний индекс.
В нашем новом статическом массиве два показателя, '0 'и '1'.
Далее в примере я назначил значения всех полей в структурированную
переменную FAMILY , в том числе и два
индекса в Children статического массива.
Вы заметите, что статические массивы имеют немного другой синтаксис для
назначения и используют квадратные скобки:
Family\Children[0] = "John"
Вы также заметили, что вам не нужно использовать команду
Dim, когда вы определяете статический
массив.
Вы просто добавляете квадратные скобки . В квадратных скобках вы
определяете нужный размер. В структуре FAMILY
выше, я
использовал строковой тип для статического массива, но вы можете
использовать любой тип и конечно же любую структуру.
Давайте рассмотрим еще один простой пример:
Structure EMPLOYEES
EmployeeName.s
EmployeeClockNumber.l
EmployeeAddress.s
EmployeeContactNumbers.l[2]
EndStructure
Dim Company.EMPLOYEES(9)
Company(0)\EmployeeName = "Bruce Dickinson"
Company(0)\EmployeeClockNumber = 666
Company(0)\EmployeeAddress = "22 Acacia Avenue"
Company(0)\EmployeeContactNumbers[0] = 0776032666
Company(0)\EmployeeContactNumbers[1] = 0205467746
Company(1)\EmployeeName = "Adrian Smith"
Company(1)\EmployeeClockNumber = 1158
Здесь я создал структуру под названием EMPLOYEES, чтобы
описать небольшую компанию сотрудников.
Затем создал стандартный массив, который содержит десять таких записей.
Внутри структуры EMPLOYEES я
использовал статический массив с типом Long для хранения двух
номеров контактного телефона.
Ну и начал определять индивидуальные сведения о сотрудниках,
начинающихся с
Company(0) \ ... , затем
Company(1) \ ..., и т.д.
Я не завершил этот пример, но я уверен, что вы поняли идею того,что я
хотел показать.
Связанные списки
Связанные списки похожи на массивы тем, что они могут сослаться на
множество данных с использованием одного имени.
Вместе с тем, они отличаются от массивов тем, что они не используют
индекс чтобы назначать и получать данные.
Эти списки похожи на книгу, в которой вы можете пролистать данные от
начала до конца или просто перейти к нужной странице
внутри, ну и конечно считать данные оттуда. Связные списки полностью
динамичны. Это означает, что они могут расти
или уменьшаться в зависимости от того, сколько данных вам нужно хранить
в них. При увеличении размеров в связанных
списках не будет вреда. Кроме того, если вам надо добавлять или
изменять какие-либо другие данные, хранящиеся в них,
вы можете спокойно это делать, не боясь за остальные данные,
причем в любом месте связанного списка.
Связные списки являются отличным способом хранения и управления
данными неопределенной длины и могут быть отсортированы
несколькими способами. Существует также встроенные библиотеки, которые
предоставляют функции для выполнения команд
добавления, удаления и замены элементов. Так же внутри библиотеки
имеются две функции, которые используются исключительно
для сортировки связанных списков, но об этом я упомяну позже.Общий
обзор встроенных команд, будет дан позднее в главе 7.
Функция NewList
Связанные списки в PureBasic создаются с помощью функции NewList, как в следующем примере:
NewList Fruit.s()
Определение связанного списка очень похоже на определение массива,
используя команду Dim. В начале мы
используем
команду NewList, чтобы сообщить компилятору, что мы собираемся
определить связанный список. Далее, мы определяем имя
нашего списка, в данном случае мы называли это Fruit. После
названия мы определяем его тип, в нашем случае String
то есть строковой. Скобки используются для определения списка. В них не
надо ничего заносить, поскольку списки
динамичны и будут расти по мере добавления элементов. Давайте
посмотрим, как мы добавим новый элемент в список:
NewList Fruit.s()
AddElement(Fruit())
Fruit() = "Banana"
AddElement(Fruit())
Fruit() = "Apple"
Поскольку связанные списки не имеют индексов, использование их на
первый взгляд кажется странным, потому что неизвестно
где какой элемент расположен. В приведенном выше примере я добавил два
новых элемента в список Fruit () .
Для этого я использовал функцию AddElement (). Когда мы
добавляем новый элемент, с помощью этой функции,
она не только автоматически определяет новый элемент, но также
делает связанную точку в списке имен,создавая пустой элемент.
А дальше мы просто используем имя списка, чтобы
присвоить этому элементу часть нужных нам данных в список.
Вместе с именем списка обязательно используем круглые скобки:
Fruit() = "Banana"
Когда мы добавляем еще один элемент помощью функции AddElement (), то происходит точно такой же процесс:
Fruit() = "Apple"
Можно подумать, что это неправильно, потому что мы присваиваем текст
Apple тому же имени, которому присвоили
текст Banana. Но если вспомнить, что мы каждый раз добавляем
новый элемент связанного списка с помощью функции AddElement (),
при всем этом сохраняя старые,то думаю все становится понятным. Мы
всегда можем проверить, сколько элементов в нашем списке, используя
функцию CountList () например:
Debug CountList(Fruit())
Если вы выполнили код выше, и дописали туда Debug CountList(Fruit()) то количество элементов, в списке Fruit() будет показано в окне отладки и равно 2.
Давайте добавим побольше элементов в этот список, а затем с помощью цикла выведем их в окно отладки:
NewList Fruit.s()
AddElement(Fruit())
Fruit() = "Banana"
AddElement(Fruit())
Fruit() = "Apple"
AddElement(Fruit())
Fruit() = "Pear"
AddElement(Fruit())
Fruit() = "Orange"
ForEach Fruit()
Debug Fruit()
Next
В этом примере, мы создали новый связанный список, называемый
Fruit() и в нем мы создали четыре
элемента
и назначили им индивидуальные значения. Затем используя цикл ForEach
мы вывели эти значения в окно отладки.
Команда ForEach используется для определения цикла, который
используется только для связанных списков.
Ниже дается краткий обзор команд для связанных списков.
Более продвинутые команды могут быть найдены в PureBasic Helpfile.
Функция | Описание |
AddElement(List()) | Добавляет элемент в список. |
ClearList(List()) | Очищает список всех элементов. |
CountList(List()) | Подсчитывает кол-во элементов внутри списка. |
DeleteElement(List()) | Удаление текущего элемента в списке |
FirstElement(List()) | Перейти к первому элементу в списке. |
InsertElement(List()) | Вставляет один элемент в список перед текущим элементом, или в начало списка, если список пуст. |
LastElement(List()) | Переход к последнему элементу в списке. |
ListIndex(List()) | Возвращает позицию текущего элемента в списке. (позиция начинается с '0 '). |
NextElement(List()) | Переход к следующему элементу в списке. |
PreviousElement(List()) | Переход к предыдущему элементу в списке. |
ResetList(List()) | Сбросить позиции списка в '0 'и сделать первый элемент текущим. |
SelectElement(List(), Position) | Сделать текущим элементом тот, что указан в параметре 'Position'. |
Структурированные Связные списки
Теперь, когда я объяснил стандартные связанные списки, давайте
перейдем к структурированным. Они аналогичны
структурированным массивам в том, что данные определяются с помощью
структуры вместо встроенных переменных.
Давайте возьмем пример с структурированными массивами, но переделаем
код под структурированные связанные списки.
Structure FISH
Kind.s
Weight.s
Color.s
EndStructure
NewList FishInTank.FISH()
AddElement(FishInTank())
FishInTank()\Kind = "Clown Fish"
FishInTank()\Weight = "4 oz."
FishInTank()\Color = "Red, White and Black"
AddElement(FishInTank())
FishInTank()\Kind = "Box Fish"
FishInTank()\Weight = "1 oz."
FishInTank()\Color = "Yellow"
AddElement(FishInTank())
FishInTank()\Kind = "Sea Horse"
FishInTank()\Weight = "2 oz."
FishInTank()\Color = "Green"
ForEach FishInTank()
Debug FishInTank()\Kind+" "+FishInTank()\Weight+"
"+FishInTank()\Color
Next
Вы можете видеть из этого примера, что после создания списка,
он очень похож на структурированный
массив. Основное различие здесь в том, что индексы массива не
используются.
Помните, что при использовании AddElement (FishInTank ())
команда создает новый элемент
с использованием структуры. Обратите внимание, нам не надо каждый раз
писать AddElement (FishInTank ()).
Вот в чем прелесть структуры! Она расширяет наш код, притом в очень
удобном виде.
Связанные списки за или против?
Связные списки прекрасно подходят для хранения данных, когда вы не
знаете, сколько их будет. Например
ранее я написал программу для отслеживания бытовых расходов, и
использовал структурированные связанные списки.
Подробная информация об этих расходах. Использование связанного списка,
было более удобным, чем массив, поскольку
проще простого было добавлять, удалять и сортировать данные.
Во время написания этой программы я думал, что я должен сделать эту
программу гибкой, чтобы работать с новыми расходами
когда они встречаются, и чтобы иметь возможность удалить старые и т.д.
Это очень хорошо обрабатывается в связанных списках. Когда мне нужно
добавить запись я использую функцию AddElement (),
когда мне нужно удалить запись я использую функцию DeleteElement ()
. После добавления и
удаления в списке, я передаю все эти данные в приятный графический
интерфейс пользователя (GUI)
чтобы увидеть и взаимодействовать. Более подробно о GUI
в главе 9.
Связные списки являются более гибкими, чем массивы в том, что они могут
расти и уменьшаться в размерах более быстро и просто.
Массивы же всегда будет использовать меньше памяти для хранения того же
объема информации, чем связанные списки. Это происходит потому,
что массивы используют непрерывную область памяти, используя
стандартный объем оперативной памяти для каждого
индекса. Связные списки отличаются таким образом, чтобы каждый элемент
использует примерно в три раза больше
RAM для определенного типа. Это происходит потому,что связанные списки
не находятся в непрерывном куске памяти.
Имейте в виду при работе с огромными массивами данных, так как ваши
требования к памяти могут быть тройными,
если вы будете использовать связанные списки.
Сортировки массивов и связанных списков
Массивы и связанные списки прекрасно подходят для хранения всех
видов данных, и эти данные проходящие через структуры могут быть легко
получены. Хотя иногда вам может потребоваться реорганизовать данные
содержащиеся в массиве или связанном списке в алфавитном порядке или
численно.
Есть несколько примеров (Helpfile:Reference Manual->General
Libraries->Sort) для сортировки массивов и связанных списков.
Сортировка стандартных массивов
Сортировка стандартных массивов чрезвычайно проста. Прежде всего,
вам необходимо иметь массив с заполнеными значениями.
Затем использовать функцию SortArray () для сортировки. Вот примерный
синтаксис:
SortArray(Array(), Options [, Start, End])
Первым делом мы задаем команду SortArray,
, что массив будет отсортирован. Обратите внимание за фигурными
скобками после имени массива стоят еще одни скобки.
Они необходимы для правильной передачи массива в качестве параметра.
Второй параметр является опциональным, чтобы указать, как массив будет
отсортирован.
Вот опциональные значения для второго параметра:
'0 ': Сортировка массива в порядке возрастания быть чувствительным к
регистру.
'1 ': Сортировка массива в порядке убывания быть чувствительным к
регистру.
'2 ': Сортировка массива в порядке возрастания, не быть чувствительным
к регистру.(' A 'такой же, как ' а ').
'3 ': Сортировка массива в порядке убывания, не быть чувствительным к
регистру.(' A 'такой же, как ' а ').
Квадратные скобки, с последними двумя параметрами показывают, что
эти не являются обязательными. Последние два параметра используются для
указания позиции внутри массива.Используя выше информацию, мы
можем сортировать массив в порядке возрастания и быть чувствительным к
регистру, с использованием
команды SortArray(Fruit(), 0):
Dim Fruit.s(3)
Fruit(0) = "Banana"
Fruit(1) = "Apple"
Fruit(2) = "Pear"
Fruit(3) = "Orange"
SortArray(Fruit(), 0)
For x.l = 0 To 3
Debug Fruit(x)
Next x
Сортировка структурированных массивов
Это будет посложнее, поскольку она использует немного более сложную
команду сортировки SortStructuredArray ().
Вот примерный синтаксис:
SortStructuredArray(Array(), Options, Offset, Type [, Start, End])
Первым параметром является имя массива со скобками. Вторым способ
сортировки, это
точно так же, как в SortArray (). Третим параметром является
смещение (позиция в теле
структуры) то есть поле, которое вы хотели бы сортировать. Можно
задавать с помощью функции OffsetOf ()
Функция OffsetOf () возвращает количество байт какой-либо
переменной от начала структуры. Четвертый параметр определяет, какой
тип переменной находится на
месте смещения. Вы можете использовать встроенные константы для
указанных параметров, для описания типа переменной:
‘#PB_Sort_Byte’
‘#PB_Sort_Character’
‘#PB_Sort_Word’
‘#PB_Sort_Long’
‘#PB_Sort_Quad’
‘#PB_Sort_Float’
‘#PB_Sort_Double’
‘#PB_Sort_String’
Последние два параметра в скобках, точно так же как и SortArray (). А теперь пример:
Structure WEAPON
Name.s
Range.l
EndStructure
Dim Weapons.WEAPON(2)
Weapons(0)\Name = "Phased Plasma Rifle"
Weapons(0)\Range = 40
Weapons(1)\Name = "SVD-Dragunov Sniper Rifle"
Weapons(1)\Range = 3800
Weapons(2)\Name = "HK-MP5 Sub-Machine Gun"
Weapons(2)\Range = 300
SortStructuredArray(Weapons(), 0, OffsetOf(WEAPON\Range), #PB_Sort_Long)
For x.l = 0 To 2
Debug Weapons(x)\Name + " : " + Str(Weapons(x)\Range)
Next x
В этом примере я выбрал поле "Range", чтобы упорядочить
структурированный массив.В команде SortStructuredArray
я определил смещение с помощью функции OffsetOf (WEAPON\Range)
и указал тип переменной поля с помощью константы # PB_Sort_Long.
Сортировка стандартного связанного списка
Сортировка стандартных связанных списков предельно проста. Прежде
всего, вам потребуется связанный список предварительно заполненный
значениями. Затем использовать функцию SortList () для
сортировки. Вот примерный синтаксис:
SortList(ListName(), Options [, Start, End])
Вначале идет название функции, и оно говорит о том что связанный список будет отсортирован. Далее в скобках задаются параметры:
1) Имя связанного списка со скобками
2) Опция сортировки (так же как у массивов выше)
3) Необязательные параметры начала и конца сортировки внутри списка
Как вы успели заметить все достаточно схоже с массивами, разница лишь в имени функции!
Использовав приведенную выше информацию, мы отсортируем список в возрастающем порядке с опцией: чувствительность к регистру:
NewList Fruit.s()
AddElement(Fruit())
Fruit() = "Banana"
AddElement(Fruit())
Fruit() = "Apple"
AddElement(Fruit())
Fruit() = "Orange"
SortList(Fruit(), 0)
ForEach Fruit()
Debug Fruit()
Next
Сортировка структурированных связанных списков
Сортировка структурированых связанных списков как и массивов немного сложнее, поскольку она использует немного более сложную функцию SortStructuredList () для сортировки. Вот пример синтаксиса этой команды:
SortStructuredList(List(), Options, Offset, Type [, Start, End])
Первой идет имя функции SortStructuredList () Далее в скобках задаются параметры:
1)Имя списка
2)Опция сортировки(так же как у массивов выше)
3)Смещение в структуре, то есть нужное поле(задается с помощью
функции
OffsetOf () )
4) Тип переменной, которая хранится в нужном поле структуры
(можно задавать константой, см. выше список констант)
5) Необязательные параметры начала и конца сортировки внутри
списка
Ну и конечно пример:
Structure GIRL
Name.s
Weight.s
EndStructure
NewList Girls.GIRL()
AddElement(Girls())
Girls()\Name = "Mia"
Girls()\Weight = "8.5 Stone"
AddElement(Girls())
Girls()\Name = "Big Rosie"
Girls()\Weight = "19 stone"
AddElement(Girls())
Girls()\Name = "Sara"
Girls()\Weight = "10 Stone"
SortStructuredList(Girls(), 0, OffsetOf(GIRL\Name), #PB_Sort_String)
ForEach Girls()
Debug Girls()\Name + " : " + Girls()\Weight
Next
В этом примере я выбрал поле "Name"
для сортировки структурированного связанного списка. Определить
смещение мне помогла функция OffsetOf (Girl \ Name),
а тип переменной я задал с помощью константы # PB_Sort_String.
Как маленькое заключение по массивам и спискам
Выбор массивов, связанных списков, структур должен зависеть от
задачи поставленной программистом. Хотя зачастую на практике, каждый
программист любит работать с более привычными для него методами
хранения данных, на мой взгляд надо все же уметь выбирать для каждой
задачи более уместный метод.
Сортировка массивов и связанных списков, созданных с помощью структур
или без них, требует правильности синтаксиса, нужных
функций и главное вашей практики. Попрактикуйтесь, и вы быстро
овладеете этим в принципе нехитрым, но мощным оружием в
программировании.
Автором данного материала является Gary Willoughby. Я лишь попробовал сделать перевод пятой части его книги для русскоязычных пользователей. Как это получилось судить вам.
С вами был Станислав Будинов.