- •Понятие данных
- •Информация и данные. Понятие о структурах данных. Информационная модель объекта
- •Понятие о данных
- •Понятие о структурах данных
- •Структуры данных и их классификация (списки, таблицы, деревья, сети).
- •Таблицы
- •Деревья
- •Понятие о типе данных в языках программирования
- •14101954
- •6. Понятие о типе данных в языках программирования (яп).
- •Декомпозиция и абстракция, их применение в программировании.
- •Абстракция и декомпозиция. Их взаимодействие при проектировании программ.
- •Абстракция – это отвлечение от всего несущественного с целью лучше понять какую-либо одну строну изучаемого предмета или явления, и в тоже время – это путь к созданию абстрактных понятий.
- •15. Реализация абстракций данных . Функция абстракции. Операции Up и Down.
- •Функция абстракции
- •Функция инвариант представления
- •Сохранение инварианта представления
- •Анализ программ, не содержащих ветвлений
- •Если p{ а }q иQ{ b }r, то выполняется p{ a;b }r.
- •P{ a;b }r.
- •Проектирование цикла с помощью инварианта Задача 1. Найти сумму величин 1/I от 1 до тех пор, пока она не станет больше некоторого наперед заданного числа a.
- •Будем искать решение нашей задачи в виде цикла, имеющего следующий вид:
Функция инвариант представления
В ориентированных на работу с типами языках (как, например, в языке CLU) контроль типов гарантирует, что если абстрактный объект типа передается как аргумент операции типа, то этот абстрактный объект представляется объектом типа представления. Во многих случаях, однако, не все объекты представления являются законными представлениями абстрактных объектов. Например, для кластера intset имеем массивы
[1: 1, 7,6], [1: 1, 6, 6] и [1:6, 1,7]. Однако в реализации intset мы решили, что каждый элемент набора записывается в массив только один раз.
Следовательно, законные представления наборов intset в этом кластере не содержат дублирующих друг друга элементов; [1: 1, 6, 6], например — незаконное представление.
Условие, которому удовлетворяют все законные объекты, называется инвариантом представления. Инвариант представления 1 есть предикат1: ( rep bool. ) который принимает значение true для законных объектов представления. Например, для кластера intset мы можем дать следующий инвариант представления:
Функция ИНВАРИАНТ ПРЕДСТАВЛЕНИЯ есть
( Для всех целых i и j таких, что
low (r)<= i < j <= high (r):(r[i] <> r[j]) )
Заметим, что для массива II:[ 1, 6, 6] 1 принимает значение false, а для массивов [1: 1, 7, 6] и [1: 6, 1, 7] — значение true. Заметим также, что мы не включаем в 1 условия, которые принимают значение true для всех массивов (например, size (r) = high (r) — low (r) + 1), потому что это гарантируется процедурами работы с массивами и соответственно предполагается в реализации intset.
В качестве второго примера инварианта представления рассмотрим альтернативное представление наборов intset, состоящее из булева массива размерности 100 и массива целых:
гер = record leis: array [bool], other.els: array [int], size: int
Идея заключается в том, что для целых от 1 до 100 мы отмечаем их принадлежность набору, записывая значение true в r.els [i] . Не принадлежащие этому диапазону целые записываются в other.els точно так же, как в нашей предыдущей реализации intset. Так как невыгодно вычислять размер набора intset, просматривая все элементы массива els, мы записываем этот размер в представление в явном виде. Это представление хорошо, если почти все члены набора принадлежат диапазону 1—100. (В противном случае пространство, требующееся для массива els, будет использоваться неэффективно.) Таким образом, мы имеем
Функция абстракции есть : А (r) = {i-.other-els [i ] I low (r. other- els) i s$high (r.other, els)}
Инвариант представления есть size (r.els) = 100 & low (r.els) = I & все элементы r.other не принадлежат диапазону I—100 & в r.other нет дубликатов элементов & r.size = size (r.other, els) - (число элементов со значением true в r.els)
Заметим, что поле size в этом представлении излишне: оно содержит информацию, которая может быть получена из остальной части представления путем вычислений. Но, поскольку такая излишняя информация все же содержится в представлении, взаимосвязь этой информации с остальной частью представления должна быть объяснена в инварианте представления (например, последняя строка нашего инварианта представления).
Иногда удобно использовать в инварианте представления или в функции абстракции вспомогательную функцию. Например, последняя строка инварианта представления может быть переписана следующим образом:
r.size= size (r.othei_els)+ cnt (r.els, low (т.els)) где cnt (a, i) = if i > high (a) then 0
else if r [i] then I+cnt (a, i+1) else cnt (a, i + 1)
Вспомогательная функция cnt определена здесь рекурсивно.
Инвариант представления должен быть явно задан также и в этом случае. Он освобождает осуществляющего реализацию от возможной зависимости от какого-то более сильного инварианта.
Инвариант представления — это «инвариант» потому, что он всегда сохраняется для представлений абстрактных объектов, т. е. он сохраняется, если объект используется вне его реализации. Инвариант представления не должен, однако, обязательно сохраняться всегда: он может быть нарушен при выполнении одной из операций типа. Инвариант представления должен сохраняться при возврате из операций.
Между функцией абстракции и инвариантом представления имеется определенная взаимосвязь. Функция абстракции имеет смысл только для законных представлений, так как только они представляют абстрактные объекты. Следовательно, нет необходимости определять ее для незаконных представлений. Существует соглашение о том, что должно быть отражено в инварианте представления.
Инвариант представления должен отражать все требования, от которых зависят операции, но может не отражать дополнительные требования. Хорошо представлять себе, что операции реализуют различные люди, которые не общаются друг с другом. Тогда понятно, что инвариант представления должен содержать все требования, которые необходимо знать этим различным людям.
При реализации абстракции данных инвариант представления — одна из первых вещей, о которых должен подумать программист. Он должен быть выбран до реализации операций, в противном случае различные реализации не будут согласованы друг с другом. Чтобы гарантировать согласованность, инвариант представления должен быть написан и включен в программу как комментарий. Написание инварианта представления вынуждает того, кто занимается реализацией, ясно выразить то, что он хочет, и увеличивает тем самым вероятность того, что операции будут реализованы корректно.
Все операции должны реализовываться с учетом инварианта представления. Например, предположим, что мы реализуем операцию insert так:
insert == proc (s: cvt, x: inl) rep$addh (s, x) end insert
Эта реализация может создать объект с дублирующимися элементами. Если мы знаем, что инвариант представления запрещает такие объекты, то эта реализация очевидно некорректна. Инвариант представления также полезен для того, кто изучает реализацию. Например, в альтернативной реализации набора intset мы можем решить подвергать массив представления сортировке. В этом случае мы будем иметь:
Инвариант представления есть: для всех i, j, таких, что low (r) < i < j < high (r): r [i] < r [j]
Все операции тогда будут реализовываться иначе. Инвариант представления говорит тому, кто изучает реализацию, почему операции реализованы именно так, как они реализованы.