- •1. Абстрагирование типов
- •1.1. Понятие типа данных
- •1.1.1. Простые типы
- •1.1.2. Абстрактные типы
- •2. Идентификация объектов
- •2.1. Именование
- •2.2. Указание
- •2.2.1. Организация адресного пространства оперативной
- •2.2.2. Понятие указателя
- •2.2.3. Действия над указателями
- •2.2.4. Связывание идентификатора объекта с его
- •3. Время жизни объекта. Классы памяти
- •3.1. Понятие “времени жизни” объекта
- •3.2. Классы памяти
- •3.2.1. Статическая память
- •3.2.2. Автоматическая память
- •3.2.3. Динамическая память
- •4. Динамические структуры данных
- •4.1. Метод вычисляемого и хранимого адреса.
- •4.2. Понятие динамической структуры данных
- •4.3. Линейные динамические структуры данных (списки)
- •4.3.1. Основные виды списков
- •4.4. Односвязные списки
- •4.4.1. Включение узла в начало списка
- •4.4.2. Создание списка из n узлов за счет добавления
- •4.4.3. Создание списка из n узлов за счет добавления
- •4.4.4. Исключение узла из начала списка
- •4.4.5. Перестановка указателя
- •4.4.6. Поиск в списке узла по заданному условию
- •4.4.7. Включение нового узла в список за тем узлом, на
- •4.4.8. Исключение из списка узла за тем узлом, на
- •4.4.9. Исключение из списка узла, на который предварительно
- •4.4.10. Разрушение списка
- •4.4.11. Программный модуль, реализующий операции
- •4.5. Односвязные циклические списки
- •4.6. Двусвязные списки
- •4.6.1. Включение нового узла в список за тем узлом, на
- •4.6.2. Исключение из списка узла, на который
- •4.7. Ортогональные списки (мультисписки)
- •4.8. Разнородные списки
- •4.9. Управление динамической памятью
- •4.9.1. Администратор кучи
- •4.9.2. Алгоритмы выделения участков памяти по запросу
- •4.9.3. Фрагментация
- •4.9.4. Накопление мусора
- •4.9.5. Висящие ссылки
- •5. Множественная интерпретация объектов
- •5.1. Совместимость типов. Приведение и преобразование типов
- •5.2. Методы совмещения типов
- •5.2.1. Запись с вариантной частью
- •5.2.2. Использование директивы absolute
- •5.2.3. Параметры без типа
- •5.2.4. Открытые массивы
- •5.2.5. Наложение масок с помощью указателей
- •6. Рекурсивные структуры данных
- •6.1. Итерация и рекурсия в программировании
- •6.1.1. Понятие рекурсии
- •6.1.2. Итеративная и рекурсивная схема организации
- •6.2. Задача о “ханойских башнях”
- •6.3. Виды рекурсивных структур данных
- •6.3.1. Арифметические выражения
- •6.3.2. Динамические линейные структуры данных: списки
- •6.3.3. Иерархические линейные структуры данных: наборы
- •6.4. Эффективность рекурсивных вычислений
- •7. ИерархическиеНелинейные структуры данных.Деревья
- •7.1. Деревья общего вида
- •7.2. Бинарные деревья
- •7.3. Представление бинарных деревьев
- •7.3.1. Представление бинарных деревьев на статической
- •7.3.2. Представление бинарных деревьев на
- •7.4. Алгоритмы обхода бинарных деревьев
- •7.5. Виды бинарных деревьев
- •7.5.1. Сбалансированные деревья
- •7.5.2. Дихотомические деревья (деревья поиска)
- •7.5.3. Деревья выражений
- •7.6. Программный модуль, реализующий операции
- •Список рекомендуемой литературы
5.2. Методы совмещения типов
Различные методы совмещения типов связаны с маскированием. Маскированиепозволяет изменить интерпретацию данных, содержащихся в элементах хранения объектов.Маска–этонекоторыйтип данных, определяющий вид интерпретации. Накладывая различные маски на одну и ту же область памяти, можно рассматривать размещенные в ней данные как принадлежащие объектам различных типов. Маскирование может быть реализовано с помощью средств, встроенных в язык программирования, или с помощью указателей. Средства языкаPASCAL, реализующие совмещение типов:
записи с вариантной частью,
директиваABSOLUTE,
параметры процедур и функций без типа,
открытые массивы.
5.2.1. Запись с вариантной частью
Запись с вариантной частьюиспользуется для работы с объектами различной структуры как с переменными одного и того же типа. Запись с вариантной частью состоит из одного или нескольких фиксированных полей (полей фиксированного размера) и единственной вариантной части, которая должна располагаться в конце записи.
Type
Rec =record
f1: integer;
case f2: boolean of
false: (f3, f4, f5: char);
true: (f6: word)
end;
Var r1,r2: rec;
Вариантная часть задается предложением вида:
Case селектор_вариантов of …
В конце вариантной части не следует ставить END как пару к CASE…OF. (Поскольку вариантная часть - всегда последняя в записи, за ней все же стоит END, но лишь как пара к RECORD). Селектор вариантов может быть именованным или неименованным, должен иметь любой порядковый тип (стандартный или пользовательский). Вариантная часть состоит из нескольких вариантов. Каждый вариант определяется константой выбора, за которой следует двоеточие и список полей данного варианта, заключенный в круглые скобки. Селектор варианта может принимать значение любой константы выбора.
Особенностью вариантной части является то, что все заданные в ней варианты “накладываются”друг на друга и используют одну и ту же область памяти (рис. 51). В элементе хранения конкретного объекта типа записи с вариантами всегда присутствует единственный вариант.
Рис. 51. Элементы хранения объектов, использующих запись с вариантной частью
Размер элемента хранения объектов, содержащих запись с вариантами, определяется размером самого длинного варианта:
Sizeof ( Rec ) = Sizeof ( f1 ) + Sizeof ( f2 ) + max { Sizeof ( f3 ) + Sizeof ( f4 ) + Sizeof ( f5 ), Sizeof ( f6 ) }.
Sizeof ( Rec ) = 6 .
Таким образом, компилятор не отводит отдельную область памяти для каждого варианта, а выделяет участок памяти, достаточный для размещения варианта самого большого размера.
При использовании именованного селектора в целях дополнительного контроля следует присваивать значение селектору перед тем, как присвоить значения полям варианта, а также проверять значение селектора перед обращением к полям варианта.
Записи с вариантами применяются для описания узлов разнородных списков. Рассмотрим разнородный список, содержащий информацию о геометрических фигурах, составляющих некоторый проект (см. 4.8). Элемент хранения узла разнородного списка содержит фиксированные поля, которые располагаются в начале записи: связь в списке, координаты точки, относительно которой строится фигура. Далее рсполагается поле селектора вариантов и поля вариантов, соответствующие трем типам геометрических фигур.
Type |
| ||||||||||
Figure = (circle, rectangle, triangle); |
{ тип фигуры } | ||||||||||
PPolygon = ^ Polygon; |
{ указатель на эл-т хранения узла разнородного списка } | ||||||||||
Polygon = record |
{ эл-т хранения узла разнородного списка } | ||||||||||
link: PPolygon; |
{ связь в списке } | ||||||||||
x,y: word; |
{ координаты точки, относительно которой строится фигура } | ||||||||||
case kind: Figure of |
{ селектор варианта, определяющий тип фигуры } | ||||||||||
circle: ( radius: word ); |
{ окружность } | ||||||||||
rectangle: ( height, width: word ); |
{ прямоугольник } | ||||||||||
triangle: ( x1,y1,x2,y2: word ) |
{ треугольник } | ||||||||||
end; |
| ||||||||||
|
| ||||||||||
Var f: PPpolygon; |
{ указатель на первый узел списка } | ||||||||||
|
| ||||||||||
{ создание элемента хранения узла и занесение его в разнородный список } | |||||||||||
Procedure Create_Node( var first: PPolygon; t: Figure ); |
{ t – тип фигуры } | ||||||||||
Var p: PPolygon; |
{ first – указатель на первый узел списка } | ||||||||||
begin |
| ||||||||||
new( p ); |
| ||||||||||
writeln( ‘введите координаты точки, относительно которой строится фигура’ ); |
| ||||||||||
write( ‘x=’ ); readln( p^.x ); |
| ||||||||||
write( ‘y=’ ); readln( p^.y ); |
| ||||||||||
p^.kind:=t; |
{ заполнение поля селектора вариантов } | ||||||||||
case t of |
{ заполнение полей вариантов в зависимости от типа фигуры: } | ||||||||||
circle: |
{ окружность } | ||||||||||
begin write( ‘введите значение радиуса = ’ ); readln( p^.radius ) end; |
| ||||||||||
rectangle: |
{ прямоугольник } | ||||||||||
begin |
| ||||||||||
write( ‘введите значение высоты = ’ ); readln( p^.height ); |
| ||||||||||
write( ‘введите значение ширины = ’ ); readln( p^.width ) |
| ||||||||||
end; |
| ||||||||||
triangle: |
{ треугольник } | ||||||||||
begin |
| ||||||||||
writeln( ‘введите координаты второй вершины’ ); |
| ||||||||||
write( ‘x=’ ); readln( p^.x1 ); |
| ||||||||||
write( ‘y=’ ); readln( p^.y1 ); |
| ||||||||||
writeln( ‘введите координаты третьей вершины’ ); |
| ||||||||||
write( ‘x=’ ); readln( p^.x2 ); |
| ||||||||||
write( ‘y=’ ); readln( p^.y2 ); |
| ||||||||||
end; |
| ||||||||||
end; |
| ||||||||||
p^.link:=first; first:=p; |
{ включение элемента хранения узла в список } | ||||||||||
end; |
| ||||||||||
|
| ||||||||||
Procedure Print( first: PPolygon ); |
{ просмотр содержимого разнородного списка } | ||||||||||
Var p: PPolygon; |
| ||||||||||
begin |
| ||||||||||
p:=first; |
| ||||||||||
while p <> nil do begin |
| ||||||||||
writeln( ‘координаты точки, относительно которой построена фигура’ ); |
| ||||||||||
writeln( ‘x= ‘, p^.x, ‘y= ‘, p^.y ); |
| ||||||||||
case p^.kind of |
{ проверка значения поля селектора вариантов: } | ||||||||||
circle: |
{ окружность } | ||||||||||
writeln( ‘радиус окружности =‘, p^.radius ); |
| ||||||||||
rectangle: |
{ прямоуглоьник } | ||||||||||
writeln( ‘высота прям-ка =’ , p^.height, ‘ширина прям-ка = ‘, p^.width ); |
| ||||||||||
triangle: |
{ треугольник } | ||||||||||
begin |
| ||||||||||
writeln( ‘координаты второй вершины треугольника‘ ); |
| ||||||||||
writeln( ‘x= ‘, p^.x1, ‘y= ‘, p^.y1 ); |
| ||||||||||
writeln( ‘координаты третьей вершины треугольника‘ ); |
| ||||||||||
writeln( ‘x= ‘, p^.x2, ‘y= ‘, p^.y2 ); |
| ||||||||||
end; |
| ||||||||||
end; |
| ||||||||||
p:=p^.link |
| ||||||||||
end; |
| ||||||||||
|
| ||||||||||
. . . |
| ||||||||||
Procedure Destroy( var first: PPolygon ); |
{ разрушение разнородного списка } | ||||||||||
begin |
| ||||||||||
. . . |
| ||||||||||
end; |
| ||||||||||
|
| ||||||||||
begin |
| ||||||||||
f:=nil; |
{ первоначально список пуст } | ||||||||||
Create_Node( f,rectangle ); |
| ||||||||||
Create_Node( f,triangle ); |
| ||||||||||
Create_Node( f,rectangle ); |
| ||||||||||
Create_Node( f,circle ); . . . |
| ||||||||||
Print( f ); . . . |
| ||||||||||
Destroy( f ); |
| ||||||||||
end. |
|
Неименованный селектор вариантов используется для приведения типов (память для него в элементе хранения объекта не отводится).
Type |
| |
Mem = record |
| |
case byte of |
| |
0: ( byt: array [1..4] of byte ); |
| |
1: ( wo: array [1..2] of word ); |
| |
2: ( l: longint ) |
| |
end; |
| |
Var m: Mem; w: word; b: byte; |
| |
begin |
| |
m.l:=123456; |
{ инициализация переменной типа Mem значением типа LongInt } | |
b:=m.byt[4]; |
{ преобразование типа Mem к типу Byte } | |
w:=m.wo[1]; |
{ преобразолвание типа Mem к типу Word } | |
. . . |
|
Sizeof ( Mem ) = 4 .
Объект mимеет три варианта, каждый из которых размещается в одном и том же элементе хранения размером 4 байта. В зависимости от того, к какому полю записи происходит обращение в программе, элемент хранения объектаmтрактуется как массив из четырех байтов, массив из двух слов или длинное целое число.