Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
83
Добавлен:
23.03.2015
Размер:
758.27 Кб
Скачать

Функция абстракции

Любая реализация абстракции данных должна определять, как представляются объекты, принадлежащие к этому типу. Выбирая представление, тот, кто занимается реализацией, учи­тывает связь между объектами представления и абстрактными объ­ектами. Предполагается, что определенные объекты представле­ния будут соответствовать, определенным абстрактным объектам.

Эта взаимосвязь может быть определена функцией, которая называется функцией абстракции. Эта функция отображает объ­екты представления в абстрактные объекты:

Здесь А обозначает набор абстрактных объектов. Для каж­дого объекта представления r, А(r) является абстрактным объ­ектом аA, который представляет r.

А: repА

Рис. 1. Пример функции абстракции.

Например, функция абстракции для реализации intset ото­бражает массив array[int] в набор intset. На рис.1 показаны отображения некоторых точек функции абстракции. Заметим, что А может отображать различные элементы в один, т.е. различным объектам представления может соответствовать один и тот же абстрактный элемент из A. Например, [1: 1, 2] и [1: 2, 1] представ­ляют один набор intset {l, 2}. В том, что функция абстракции часто отображает различные элементы в один, нет ничего удиви­тельного, так как процесс абстракции отбрасывает не относя­щуюся к делу информацию. В этом примере такая информация — это расположение элементов в массиве.

Функция абстракции – это важнейшая информация о реали­зации. Она определяет конкретное представление, т.е. то, каким образом объекты представления реализуют абстрактные объ­екты. Эта функция должна быть обязательно представлена в комментариях реализации. Описывая функцию реализации, мы иногда сталкиваемся с проблемой, связанной с тем, что, если спецификация типа неформальная, область изменения функции абстракции не может быть точно определена. Сейчас мы будем преодолевать эту проблему с помощью неформального описания «типичного» абстрактного объекта.

Для определения функции абстракции прежде всего опреде­ляем типичный элемент абстрактного типа. Это дает нам воз­можность говорить об абстрактных объектах. Затем можем оп­ределить функцию абстракции в терминах этого типичного объ­екта. Например, для наборов intset вы можете дать следующее описание:

Типичный набор intset есть {х1, ... хn}

Здесь для описания наборов intset используем понятие мате­матического набора, точно так же, как делали это в специфи­кации intset. Затем пишем

/*Функция абстракции есть

А(r) = {r[i] | low(r) i high(r)},

*/

где {x | p(x)} есть набор всех таких х, что р(х) имеет значение true.

В качестве другого примера рассмотрим полиномы. Мы ре­шаем представлять полином массивом, в котором i-й элемент содержит i-й коэффициент, если этот коэффициент не относится к нулевым коэффициентам справа или слева от значащих чле­нов полинома. Это представление описываем следующим образом:

/*Типичный полином есть: c0 + c1x + c2x2+ ...

Функция абстракции для коэффициента с1 есть

ci = г [i], если low(r)  i  high (r)

= 0 в противном случае

*/

Эта функция абстракции определена только для массивов с неотрицательной нижней границей. Функции абстракции часто имеют заданные области определения, как, например, в рас­сматриваемом случае.

Функция абстракции, в частности, удобна тем, что устраняет двусмысленности в интерпретации представления. Например, предположим, что с помощью массивов мы реализуем стеки. Мы можем выбирать, каким образом увеличивать массив, когда в стек добавляется новый элемент. Этот наш выбор будет отражен в функции абстракции. Если вы решаете увеличивать старший ин­декс массива и по этому индексу записывать элемент, то функция абстракции будет следующая:

/*Типичный стек – это последовательность [е1,...,еn], где

еn – элемент со старшим индексом

Функция абстракции есть

А(г) = [r[low (r)], ..., r [high (r)]]

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

А(r) = [r[high(r)], ..., r[low(r)]]

*/

Заметим, что реализации стеков, о которых только что го­ворилось, используют одно и то же представление, которое интер­претируется, однако, по-разному.

Пример функции абстракции для стека

╔════════════════════════════════════════════════════════╗

║ Дескриптор стека REP(Представление стека) ║

║ ┌────────────┐ ========================= ║

S1─────╫─>│Size│ ║

║ ├────────────┤ ║

║ │ TopInd│ ║

║ ├────────────┤ ║

║ │ PBody│ ║

║ └─────┼──────┘ ║

║ │ ║

║ ┌─────┼─────────────────────────────────────────────┐ ║

║ │ │ Тело стека │ ║

║ │ │ ┌───────────┐ │ ║

║ │ │ Size│-----------│ │ ║

║ │ │ ├───────────┤ │ ║

║ │ │ ...│-Свободно--│ │ ║

║ │ │ ├───────────┤ │ ║

║ │ │ │-----------│ │ ║

║ │ │ ├───────────┤ │ ║

║ │ │ TopInd│///////////│ Вершина │ ║

║ │ │ ├───────────┤ │ ║

║ │ │ ...│///////////│ │ ║

║ │ │ ├───────────┤ │ ║

║ │ │ 3 │/Заполнено/│ │ ║

║ │ │ ├───────────┤ │ ║

║ │ │ 2 │///////////│ │ ║

║ │ │ ├───────────┤ │ ║

║ │ └────────> 1 │///////////│ │ ║

║ │ └───────────┘ │ ║

║ │ ////////////////////// │ ║

║ │ //// Дно стека //// │ ║

║ └───────────────────────────────────────────────────┘ ║

╚════════════════════════════════════════════════════════╝

=================================== Тищенко =============================

Вопрос № 16 :

Реализация абстракции данных. Функция инвариант представления. Сохранения инварианта представления.

Реализация абстракций данных

Для реализации типа данных мы выбираем представление для объектов и реализуем операции в терминах этого представ­ления. Выбранное представление должно предоставлять возмож­ности для довольно простой и эффективной реализации всех операций. Кроме того, если некоторые операции должны выполняться быстро, представление должно предоставлять и эту воз­можность. Часто представление, обеспечивающее быструю ра­боту некоторых операций, приводит к тому, что другие операции выполняются медленно. В этом случае мы должны использовать несколько различных реализаций одного и того же типа.

Например, возможное представление для объекта intset — это массив целых чисел, где каждое целое число набора intset соответствует элементу массива. Мы должны решить — должен ли каждый элемент набора встречаться в массиве только один раз или же он может встречаться много раз. В последнем случае опе­рация insert будет работать быстрее, однако операции delete и member будут выполняться медленнее. Если операция mem­ber используется часто, мы должны остановиться на первом слу­чае.

Заметим, что здесь мы говорим о двух разных типах: новом абстрактном типе intset, который мы реализуем, и массиве целых, который используется как представление. Каждая реализация будет иметь два таких типа: абстрактный тип и тип представ­ления (rep type). Предполагается, что с типом представления мы имеем дело только при реализации. Все, что мы можем делать с объектами абстрактного типа, — это применять к ним соответ­ствующие данному типу операции. Соблюдение этого ограниче­ния в языке CLU осуществляется с помощью контроля типов. Язык CLU удобен, поскольку в нем тип может быть реализован как отдельный программный модуль. Эта программная единица языка CLU называется кластер. Отсюда и название (CLU от слова CLUster.)

Внутри кластера должны быть доступны как абстрактный тип, так и тип представления. Более того, должна иметься воз­можность перехода от одного типа к другому. Например, опера­ция insert получает в качестве аргумента набор целых чисел, но для реализации insert необходимо использовать массив, который представляет этот набор.

Возможность перехода от абстрактного типа к типу представ­ления и обратно в языке CLU обеспечивают две специальные операции: up и down. Операция up использует в качестве аргу­мента объект представления и в качестве результата выдает абстрактный объект, а операция down осуществляет обратное действие. Для того чтобы обеспечить преобразование абстрактного типа в тип представления и обратно, каждый кластер имеет свою собственную версию операций up и down. Эти операции автоматически определяются компилятором CLU. Например, в кластере процедуры intset компилятор порождает операции up и down со следующими заголовками:

up = proc (a: array [int]) returns (intset) down = proc (s: intset) returns (array [int])

Операции up и down могут использоваться только в кластерах и всегда осуществляют переход от абстрактного типа к типу пред­ставления и обратно только для кластера, в котором они появи­лись. Поэтому операции up и down не могут отрицательно по­влиять на контроль типов языка CLU.

Соседние файлы в папке POSIBNIK