- •Понятие данных
- •Информация и данные. Понятие о структурах данных. Информационная модель объекта
- •Понятие о данных
- •Понятие о структурах данных
- •Структуры данных и их классификация (списки, таблицы, деревья, сети).
- •Таблицы
- •Деревья
- •Понятие о типе данных в языках программирования
- •14101954
- •6. Понятие о типе данных в языках программирования (яп).
- •Декомпозиция и абстракция, их применение в программировании.
- •Абстракция и декомпозиция. Их взаимодействие при проектировании программ.
- •Абстракция – это отвлечение от всего несущественного с целью лучше понять какую-либо одну строну изучаемого предмета или явления, и в тоже время – это путь к созданию абстрактных понятий.
- •15. Реализация абстракций данных . Функция абстракции. Операции Up и Down.
- •Функция абстракции
- •Функция инвариант представления
- •Сохранение инварианта представления
- •Анализ программ, не содержащих ветвлений
- •Если p{ а }q иQ{ b }r, то выполняется p{ a;b }r.
- •P{ a;b }r.
- •Проектирование цикла с помощью инварианта Задача 1. Найти сумму величин 1/I от 1 до тех пор, пока она не станет больше некоторого наперед заданного числа a.
- •Будем искать решение нашей задачи в виде цикла, имеющего следующий вид:
15. Реализация абстракций данных . Функция абстракции. Операции Up и Down.
Реализация абстракций данных
Для реализации типа данных нужно выбирать представление для объектов и реализовать операции в терминах этого представления. Выбранное представление должно предоставлять возможности для довольно простой и эффективной реализации всех операций. Кроме того, если некоторые операции должны выполняться быстро, представление должно предоставлять и эту возможность. Часто представление, обеспечивающее быструю работу некоторых операций, приводит к тому, что другие операции выполняются медленно. В этом случае вы должны использовать несколько различных реализаций одного и того же типа.
Например, возможное представление для объекта intset — это массив целых чисел, где каждое целое число набора intset соответствует элементу массива. Вы должны решить — должен ли каждый элемент набора встречаться в массиве только один раз или же он может встречаться много раз. В последнем случае операция insert будет работать быстрее, однако операции delete и member будут выполняться медленнее. Если операция member используется часто, мы должны остановиться на первом случае.
Заметим, что здесь говорится о двух разных типах: новом абстрактном типе intset, который реализуем, и массиве целых, который используется как представление. Каждая реализация будет иметь два таких типа: абстрактный тип и тип представления (rep type). Предполагается, что с типом представления вы имеете дело только при реализации. Все, что вы можете делать с объектами абстрактного типа, — это применять к ним соответствующие данному типу операции. Соблюдение этого ограничения в языке CLU осуществляется с помощью контроля типов.
Вот пример как реализовать абстракции данных на языке CLU
Хотя, конечно, возможно реализовать типы на языках, которые специально не приспособлены для этой цели, более удобно, если тип может быть реализован как отдельный программный модуль. Язык CLU предоставляет такую программную единицу. Эта единица называется кластер. (CLU, отметим, — это первые три буквы слова cluster.) Кластер включает в себя следующее.
1. Заголовок, в котором придаются имена реализуемому типу и операциям. Этот заголовок похож на заголовок в спецификации.
2. Определение представления, выбранного в данной реализации.
3. Реализации примитивных операций. Дополнительные программы (процедуры и итераторы) также могут быть включены в кластер, но обращаться извне можно только к тем, которым приданы имена в заголовке.
Общий вид кластера
dnarne = cluster is % список имен операций rep = и здесь дается описание представления
% здесь помещаются реализации операций
% если необходимо, здесь могут быть представлены вспомогательные программы
end dnarne
Для представления наборов целых чисел с помощью массивов, например, мы указываем
гер = array [int ]
Эта строка выполняет две функции) информирует компилятор CLU о том, что в этом кластере представлением является массив целых чисел и что в теле кластера обозначение гер может использоваться в качестве аббревиатуры для этого представленного массивом типа.
Внутри кластера должны быть доступны как абстрактный тип, так и тип представления. Более того, должна иметься возможность перехода от одного типа к другому. Например, операция 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.
Хотя операции up и down могут появиться, где угодно, среди операций кластера, они в основном используются в одном из двух случаев. В первом случае, когда операция использует в качестве аргумента абстрактный объект, для преобразования этого объекта в тип представления используется операция down. Во втором случае, когда операция возвращает заново созданный абстрактный объект, сразу же перед возвратом для преобразования объекта представления в абстрактный тип используется операция up. Для удобства работы язык CLU предоставляет специально зарезервированное слово cvt. Слово cvt может использоваться как тип аргумента или результата в заголовках операций кластеров. Использование его как типа аргумента указывает, что фактический аргумент — абстрактного типа, неформальный — типа представления и что поэтому к фактическому аргументу сразу же после вызова должна быть неявно применена операция down и результирующий объект представления должен быть присвоен формальному аргументу. Когда cvt используется как тип результата, это означает, что результирующий объект — абстрактного типа, но возвращаемый объект—типа представления и что поэтому прямо перед возвратом к возвращаемому объекту неявно должна быть применена операция up. Слово cvt не добавляет никакой функциональности, которая не была бы обеспечена операциями up и down. Оно обеспечивает только удобство, которое возникает из возможности довольно просто описывать общие случаи.
Реализации процедуры intset.
intset == cluster is create, insert, delete, member, size, choose rep = array [int]
create = proc ( ) returns (cvt) return (rep$new ( )) end create
insert = proc (s: intset, x: int)
if — member (s, x) then rep$addh (down (s), x) end end insert
delete = proc (s: cvt, x: int) j: int :== getind (s, x) if j <= rep$high (s) then s [j] := rep$top (s) % top возвращает s [high (s)]
rep$remh (s) end end delete
member = proc (s: cvt, x: int) returns (bool) return (getind (s, x) <= rep$high (s)) end member
size = proc (s: cvt) returns (int^ return (rep$size (s)) end size
choose = proc (s: cvt) returns (int)
return (rep$bottom (s)) % bottom возвращает s [low (s) ] end choose
getind = proc (s: rep, x: int) returns (int) i: int : = rep$low (s) while i (= rep$high (s) do if x = s [i] then return (i) end i:=i+ I end return (i) end getind
end intset
Операции up и down
Полезно представлять себе операцию up как окружение объекта типа представления непроницаемой заслонкой. Тому, кто использует операцию up, сквозь эту заслонку не видно представления. Значение объекта можно исследовать только вызовом примитивных операций, соответствующих типу объекта. Например, пользователь не видит массива, который представляет набор intset, но может сказать, какие элементы имеются в наборе, и может добавлять или удалять элементы, обращаясь к соответствующим операциям.
Операция down производит обратное действие по отношению к up — она убирает заслонку. Если бы для пользователя имелась возможность обращаться к down, то ему было бы доступно конкретное представление абстрактного объекта и выгоды абстракции данных были бы утеряны. Поэтому язык CLU позволяет использовать операцию down только в кластере, который реализует объект.
Чтобы избежать возникновения фальшивых объектов, ограничивается также и использование операции up. Если бы эту операцию можно было использовать вне определяющего кластера, было бы возможно создавать объекты, которые выглядели как объекты типа, но которые при передаче их операциям кластера в качестве аргумента имели бы другое, чем ожидается, представление, что приводило бы к всевозможным очень неприятным ошибкам. Поэтому, чтобы использование абстракций данных было выгодно, ограничение сферы применения операций up и down необходимо.
Как уже говорилось, если операция down используется внутри кластера, то она убирает заслонку и представление объекта становится видимым. Однако это представление есть просто другой абстрактный объект, и он защищен заслонкой, сконструированной его собственной реализацией, которая может быть либо определенным пользователем кластером, либо частью реализации языка CLU. Реальное представление объекта снова недоступно, но информация об объекте может быть получена при помощи операций. Так, внутри кластера intset нам недоступна внутренняя структура массива, который реализует intset, но вы можете исследовать и изменять интересующую нас информацию, используя операции работы с массивом.
Для операций up и down (и следовательно, для cvt) не генерируется никакого объектного кода. Они лишь информируют компилятор о том, что способ рассмотрения объекта изменился. Компилятор использует эту информацию для контроля типов. Так как контроль типов производится во время компиляции, эта информация не нужна при выполнении, хотя она и может быть полезна для отладки.