Абстрактное нотация для записи определений функций. Смотреть что такое "Абстрактный тип данных" в других словарях. Специальные виды множеств

Последнее обновление: 04.08.2018

Кроме обычных классов в C# есть абстрактные классы . Абстрактный класс похож на обычный класс. Он также может иметь переменные, методы, конструкторы, свойства. Единственное, что при определении абстрактных классов используется ключевое слово abstract :

Abstract class Human { public int Length { get; set; } public double Weight { get; set; } }

Но главное отличие состоит в том, что мы не можем использовать конструктор абстрактного класса для создания его объекта. Например, следующим образом:

Human h = new Human();

Зачем нужны абстрактные классы? Допустим, в нашей программе для банковского сектора мы можем определить две основных сущности: клиента банка и сотрудника банка. Каждая из этих сущностей будет отличаться, например, для сотрудника надо определить его должность, а для клиента - сумму на счете. Соответственно клиент и сотрудник будут составлять отдельные классы Client и Employee. В то же время обе этих сущности могут иметь что-то общее, например, имя и фамилию, какую-то другую общую функциональность. И эту общую функциональность лучше вынести в какой-то отдельный класс, например, Person, который описывает человека. То есть классы Employee (сотрудник) и Client (клиент банка) будут производными от класса Person. И так как все объекты в нашей системе будут представлять либо сотрудника банка, либо клиента, то напрямую мы от класса Person создавать объекты не будем. Поэтому имеет смысл сделать его абстрактным:

Abstract class Person { public string Name { get; set; } public Person(string name) { Name = name; } public void Display() { Console.WriteLine(Name); } } class Client: Person { public int Sum { get; set; } // сумма на счету public Client(string name, int sum) : base(name) { Sum = sum; } } class Employee: Person { public string Position { get; set; } // должность public Employee(string name, string position) : base(name) { Position = position; } }

Затем мы сможем использовать эти классы:

Client client = new Client("Tom", 500); Employee employee = new Employee ("Bob", "Apple"); client.Display(); employee.Display();

Или даже так:

Person client = new Client("Tom", 500); Person employee = new Employee ("Bob", "Операционист");

Но мы НЕ можем создать объект Person, используя конструктор класса Person:

Person person = new Person ("Bill");

Однако несмотря на то, что напрямую мы не можем вызвать конструктор класса Person для создания объекта, тем не менее конструктор в абстрактных классах то же может играть важную роль, в частности, инициализировать некоторые общие для производных классов переменные и свойства, как в случае со свойством Name. И хотя в примере выше конструктор класса Person не вызывается, тем не менее производные классы Client и Employee могут обращаться к нему.

Абстрактные члены классов

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

  • Свойства

    Индексаторы

Абстрактные члены классов не должны иметь модификатор private. При этом производный класс обязан переопределить и реализовать все абстрактные методы и свойства, которые имеются в базовом абстрактном классе. При переопределении в производном классе такой метод или свойство также объявляются с модификатором override (как и при обычном переопределении виртуальных методов и свойств). Также следует учесть, что если класс имеет хотя бы одный абстрактный метод (или абстрактные свойство, индексатор, событие), то этот класс должен быть определен как абстрактный .

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

Абстрактные методы

Например, сделаем в примере выше метод Display абстрактным:

Abstract class Person { public string Name { get; set; } public Person(string name) { Name = name; } public abstract void Display(); } class Client: Person { public int Sum { get; set; } // сумма на счету public Client(string name, int sum) : base(name) { Sum = sum; } public override void Display() { Console.WriteLine($"{Name} имеет счет на сумму {Sum}"); } } class Employee: Person { public string Position { get; set; } // должность public Employee(string name, string position) : base(name) { Position = position; } public override void Display() { Console.WriteLine($"{Position} {Name}"); } }

Абстрактные свойства

Следует отметить использование абстрактных свойств. Их определение похоже на определение автосвойств. Например:

Abstract class Person { public abstract string Name { get; set; } } class Client: Person { private string name; public override string Name { get { return "Mr/Ms. " + name; } set { name = value; } } } class Employee: Person { public override string Name { get; set; } }

В классе Person определено абстрактное свойство Name. Оно похоже на автосвойство, но это не автосвойство. Так как данное свойство не должно иметь реализацию, то оно имеет только пустые блоки get и set. В производных классах мы можем переопределить это свойство, сделав его полноценным свойством (как в классе Client), либо же сделав его автоматическим (как в классе Employee).

Отказ от реализации абстрактных членов

Производный класс обязан реализовать все абстрактные члены базового класса. Однако мы можем отказаться от реализации, но в этом случае производный класс также должен быть определен как абстрактный:

Abstract class Person { public abstract string Name { get; set; } } abstract class Manager: Person { }

Пример абстрактного класса

Xрестоматийным примером является система геометрических фигур. В реальности не существует геометрической фигуры как таковой. Есть круг, прямоугольник, квадрат, но просто фигуры нет. Однако же и круг, и прямоугольник имеют что-то общее и являются фигурами:

// абстрактный класс фигуры abstract class Figure { // абстрактный метод для получения периметра public abstract float Perimeter(); // абстрактный метод для получения площади public abstract float Area(); } // производный класс прямоугольника class Rectangle: Figure { public float Width { get; set; } public float Height { get; set; } public Rectangle(float width, float height) { this.Width = width; this.Height = height; } // переопределение получения периметра public override float Perimeter() { return Width * 2 + Height * 2; } // переопрелеление получения площади public override float Area() { return Width * Height; } }

Абстрактным принято называть тип данных, в явном виде не имеющийся в языке программирования, в этом смысле это понятие относительное - тип данных, отсутствующий в одном языке программирования, может присутствовать в другом.

Абстрактный тип данных (АТД) определяется независимо от способа его реализации:

§ множеством возможных значений этого типа,

§ и набором операций со значениями этого типа.

Использование АТД может быть ограничено этапом разработки программного обеспечения, но для его явного использования в программе надо иметь его реализацию на основе уже имеющихся (и ранее реализованных) типов данных в языке программирования:

§ способ представления значений этого типа,

§ и реализацию операций со значениями этого типа.

АТД не является предопределенным в языке программирования, и даже более того – операции конструирования таких типов, предопределенные в языке, перекладывают на разработчика-программиста вопрос о способе представления значений такого типа и реализации операций со значениями этого типа. А потому, для таких типов данных вопрос о выборе определений и способов реализации операций вида конструктор (значений и хранилищ данных) такого типа, селектор и модификатор компонентов (значений и хранилищ данных) такого типа возлагается на разработчика-программиста.

В концепции АТД особый статус имеют понятия интерфейс , открытый пользователю, и реализация , скрытая от него. Особая роль этих понятий в концепции АТД связана с основополагающим положением о независимости понятия АТД от способа его реализации.

В современных «практических языках программирования» для конструирования АТД обычно используется предопределенная операция конструирования типов class , которая дает разработчику-программисту не только средства группировки данных и операций (с этими данными) в единое целое, но и средства инкапсуляции, наследования и полиморфизма для управления способами конструирования и доступа к таким данным. Отметим, что класс описывает одну возможную реализацию АТД, отображение класса в АТД выражается функцией абстракции, но обратное отношение, обычно, не является функциональным, реализаций одного и того же АТД может быть несколько.



В исследованиях по абстрактным типам данных уже на раннем этапе была осознана важная роль понятия «параметризация типа ». Действительно, например АТД «Стек» не зависит от типа элементов стека, но реализовать этот АТД указанием на «элементы какого-то одинакового типа» невозможно. В язык программирования Ada соответствующие средства конструирования параметризованных типов данных были включены изначально, а в современных «практических языках программирования» какие средства появились только со времен появления разработки по STL-библиотеке . На сегодня понятие «обобщенное программирование» занимает значимое положение в практическом программировании благодаря включению в «практические языки программирования» средств конструирования параметризованных типов данных (шаблоны, template , generic) .

Всё вышесказанное означает, что с методологической и теоретической точки зрения необходимо более детальное точное определение понятия «абстрактный тип данных». В теории понятие «абстрактный тип данных» обычно определяется как многосортная (многоосновная) алгебраическая система , в которой дополнительно к множеству возможных значений (носителю) и набору операций над такими значениями выделены понятия:

§ Сорт и сигнатура – эти понятия позволяют расклассифицировать и элементы носителя и операции с ними по их типам (для операций - по типам их аргументов и возвращаемого значения).

§ Предикаты – отношения на элементах носителя. Это позволяет определять область возможных значений наложением ограничений (требований) на допустимые значения, а также в естественной трактовке работать с произвольными логическими выражениями, не принуждая интерпретировать их как функции принадлежности для множеств или как многозначные операции.

На такой основе можно рассматривать абстрактные типы данных с единой целостной логико-алгебраической точки зрения, включая вопросы о конструкторах (типов и значений), селекторах и модификаторах свойств для объектов такого типа .

Понятия «структура данных» и «абстрактный тип данных» в чем-то очень близкие. Можно конечно считать, что эти понятия - просто два взгляда на одно и то же. Способ представления значений АТД всегда основан на некоторой структуре данных, менее или более сложной, и реализация операций с такими значениями естественно зависит от этой выбранной структуры данных. С другой стороны, заинтересовавшую нас структуру данных при большом желании мы всегда можем оформить как АТД.

Но все же мы будем различать эти два понятия, учитывая:

§ Абстрактный тип данных - подразумевает определенный уровень абстрагирования с целью фиксации прикладного (предметно-ориентированного) типа данных безотносительно к способам его реализации, и возможно включения этого типа данных в прикладную библиотеку, ну хотя бы для конкретной разработки конкретной программной системы. АТД может иметь несколько альтернативных реализаций, основанных на различных структурах данных.

§ Структура данных - скорее некоторая схема организации данных и управления ими, которая предполагает соответствующие конкретизации при ее использовании в конкретных ситуациях при решении конкретных задач.

К абстрактным типам данных прежде всего естественно относятся математические базовые алгебраические системы – последовательности, множества, отношения и отображения (функциональные отношения, функции) . Но в программировании на переднем плане не исследование общих свойств этих математических понятий, а возможности их использования в разработке моделей решения задач предметной области, алгоритмов решения этих задач и эффективной реализации разработанных алгоритмов. А потому в программировании в виде АТД обычно оформляются с одной стороны ограниченные варианты этих базовых алгебраических систем, а с другой стороны расширенные специализированными наборами операций, представляющими прагматический интерес с точки зрения области применения.

2.1. Последовательность (Sequence).

Бесконечная (конечная) последовательность формально определяется как функция, областью определения которой является множество положительных целых чисел: f(i)= , . Во многих случаях индексирование последовательности более удобно начинать с нуля; тогда областью определения / будет множество целых неотрицательных чисел. Аналогично определим конечную последовательность или список как функцию, областью определения которой является множество {1, 2, ..., }.

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

¨ Множество возможных значений – конечные последовательности элементов одинакового типа.

¨ Набор операций:

§ Вставить элемент в последовательность.

§ Удалить элемент из последовательности.

§ Посмотреть – функция, возвращающая значение элемента последовательности.

Разновидности этого вида АТД различаются способом доступа к элементам последовательности и ограничениями на место вставки и удаления элементов.

Для АТД этого вида стек (stack) , очередь (queue) и дек (deque от Double Ended Queue - двусторонняя очередь) характерно разрушающее чтение , т.к. доступ к элементам (для всех трех операций) ограничен одним из концов последовательности и операцию «посмотреть другой элемент» можно выполнить, только удалив мешающие этому элементы. Для АТД вектор(array, vector),файл (file) и линейный список (linear list) ограничения на доступ обеспечивают неразрушающее чтение , поэтому особое значение имеет (производная) операция просмотра последовательности .

Ограничения на доступ к элементам последовательности естественно отражаются на семантике основных операций. Последовательный доступ основан на понятии текущая позиция и допускает доступ (перемещение, навигацию) к одному (или к обоим) из концов последовательности и к соседней позиции (слева, справа или к обеим) относительно текущей. Место применения основных операций в этом случае обычно привязывается к текущей позиции. Прямой (позиционный, произвольный) доступ основан на глобальном понятии позиция элемента в последовательности и обеспечивает непосредственный доступ к элементу, если известна его позиция. Например, в АТД динамический вектор (dynamic array, vector) , позиция – это индекс элемента. Но в других реализациях других видов последовательностей идентификатор позиции может быть реализован иначе.

Понятия «номер» и «позиция» элемента – близкие, но могут не совпадать:

§ Номер - это собственно порядковый номер элемента в последовательности. Но порядковый номер элемента изменяется в результате выполнения операций вставки и удаления предшествующих элементов, это создает ряд неудобств в идентификации элементов последовательности.

§ Позиция - аналогична порядковому номеру в том смысле, что для элемента в заданной позиции позволяет говорить о предшествующем и следующем элементе последовательности (и их позиции). Но значение позиции элемента не изменяется в результате выполнения операций вставки и удаления предшествующих элементов, поэтому значение позиции элемента можно сохранить и использовать для доступа к этому элементу в будущем. Например, в реализации последовательности связным списком понятие «позиция» может быть представлено указателем на элемент, а в других реализациях может быть представлено идентификатором другого вида, специально поддерживаемым реализацией.

Для АТД «Последовательность» представляют интерес дополнительные операции вида: сцепить две последовательности, расцепить на две последовательности. Например, в АТД строка(string) такого вида операции фактически являются основными.

Для различных видов АТД «Последовательность» достижима различающаяся эффективность реализации различных операций. Например, если реализация предлагает эффективный прямой доступ к элементам последовательности, то скорее всего – время выполнения операции вставки в середине последовательности оставляет желать лучшего. Различные виды (и реализации) АТД «Последовательность» выдвигают программисту различные предложения и по составу операций и по эффективности их реализации. А потому в практике программирования обычно больший интерес представляют не столько универсальные варианты этого (как и других) АТД, а скорее специализированные, и программист должен проводить соответствующий выбор с учетом их использования в решении задач предметной области.

2.2. Множество (Set).

¨ Множество возможных значений – конечные множества элементов одинакового типа.

¨ Набор операций:

§ Вставить элемент во множество.

§ Удалить элемент из множества.

§ Принадлежать – функция, возвращающая значение true, если элемент принадлежит множеству.

Для такого фундаментального понятия классической математики представляется естественным расширить набор операций до типового классического. Но по ряду причин прагматического характера в программировании такое АТД общего (универсального) вида представляет ограниченный интерес. Например, включение операции объединения пересекающихся множеств, при реализации требует удаления элементов пересечения. Это может значительно усложнить реализацию этой операции. С другой стороны наличие дубликатов может быть некритичным с позиции решаемой задачи, в этом случае АТД представляют собой мультимножества. Фундаментальное значение понятия множества, конечно, проявляется наличием богатого набора специализированных расширений этого базового АТД «Множество», которые широко используются в практике программирования, как благодаря мощной выразительной силе этого инструментария в разработке модели задач и алгоритмов их решения, так и благодаря наличию эффективных методов реализации этих АТД.

Специализированные расширения АТД «Множество» рассматриваются в различных направлениях:

§ Близким к понятию «множество» является понятие «набор». Набор (Bag, MultiSet) – также как и множество является семейством элементов, безотносительно к тому задано ли на элементах отношение порядка, но элементы в наборе могут повторяться по значению. Вообще говоря, набор можно представить множеством, например, элементы которого являются парами [значение элемента, количество вхождений в набор].

§ В практических приложениях часто элементы множеств идентифицируются, т.е. элемент является парой [ключ элемента, собственно значение элемента], АТД «Словарь» - пример такого специализированного расширения АТД «Множество». Предпочтительный случай, когда ключ элемента – уникальный , т.е. множество не может содержать двух элементов с одинаковым ключом. Но возможно, что используемый ключ неуникальный, т.е. неоднозначно идентифицирущий собственно значение элемента. Вообще говоря, множество (и набор) с неуникальным ключом можно представить множеством с уникальным ключом, усложнив тип значения элемента, например, рассматривая в качестве значения элемента множество значений предыдущего типа (с одинаковым ключом).

§ Естественным представляется задание на множестве отношения порядка, частичного или линейного, АТД «Очередь с приоритетом» - пример такого специализированного расширения АТД «Множество». Аналогично в предметной области решаемой задачи могут представлять интерес и другие отношения на множестве .

§ Фундаментальное положение в математике занимает понятие отношение эквивалентности и соответственно – понятие разбиение множества на классы эквивалентности. Естественно, что это понятие широко используется и в практических разработках моделей решения задач предметных областей. АТД «Семейство непересекающихся множеств» (Disjoint Sets, Partitions, Разбиения) - пример соответствующего специализированного расширения АТД «Множество».

Для специализированных расширений АТД «Множество» естественно соответствующим образом уточняются вышеотмеченные операции и появляются свои новые операции, представляющие интерес.

2.3. Словарь (Dictionary, Map), другое название – ассоциативный массив .

¨ Множество возможных значений – конечные множества элементов одинакового типа, вида , где Key – уникальный ключ элемента, Value - собственно значение.

¨ Набор операций:

§ Вставить элемент (с ключом) во множество.

§ Удалить элемент (заданный ключом) из множества.

§ Найти элемент – функция, возвращающая по ключу значение элемента или «пустое» значение, если элемента с таким ключом нет во множестве.

АТД «Словарь» - это специализированный вариант понятия (хранимое) отображение (ключей в значения), широко используемый в практическом программировании. Но для некоторых предметных областей возможно более удобным окажется оформление АТД «Отображение» (Mapping) , более близкое классическому математическому определению .

2.4. Очередь с приоритетом (Priority queue).

¨ Множество возможных значений – конечные множества элементов одинакового типа. На множествах (возможных значениях) задано отношение линейного порядка, которое трактуется как сравнение элементов по приоритетности. Уровень приоритета может быть выделен как составная часть значения элемента или вычислим заданной функцией от значения элемента.

Отметим, что такое множество возможных значений можно трактовать и как множество последовательностей (с перечислением её элементов в заданном линейном порядке).

¨ Набор операций:

§ Вставить элемент в (линейно упорядоченное) множество.

§ Удалить минимальный элемент из множества.

§ Найти минимальный – функция, возвращающая значение минимального элемента во множестве.

Рассматриваются также (существенные) вариации этого АТД с дополнительными операциями:

§ Расцепить очередь на две по заданному значению (приоритету) элемента – на очередь элементов с меньшим приоритетом и очередь остальных.

§ Сцепить две очереди, у одной из которых все элементы имеют приоритет больший, чем у всех элементов другой очереди в одну очередь с приоритетом без сохранения исходных сцепляемых очередей.

§ Объединить два непересекающихся упорядоченных множества (слить две такие очереди) в одно упорядоченное множество (одну очередь с приоритетом), также без сохранения исходных объединяемых.

§ Уменьшить значение (приоритет) заданного элемента.

§ Удалить (произвольно) заданный элемент из множества.

2.5. Непересекающиеся множества (Disjoint Sets, Partitions, Разбиения) .

¨ Множество возможных значений – конечные множества (семейства) непересекающихся конечных множеств. Элементы семейства идентифицированы, т.е. каждое множество из семейства имеет (уникальное) имя.

¨ Набор операций:

§ Объединить(А,В) – операция вида А:= А È В без сохранения исходных объединяемых множеств (а значит новое значение семейства останется семейством непересекающихся множеств, причем их количество уменьшится).

§ Найти множество – функция, возвращающая для заданного х имя такого множества Х в семействе, что х Î Х.

2.6. Деревья, графы и отношения общего вида.

В дискретной математике особое внимание уделяется (конечным) отношениям вида - дерево, граф и сеть (мультиграф, гиперграф), имеющим определенно выраженную геометрическую трактовку:

¨ Граф – (конечное) бинарное отношение (симметричное – в случае неориентированных графов), E Í V 2 , где V – множество вершин, а E – множество ребер графа.

В дискретной математике обычно E определяется не как множество, а как набор ребер графа, это позволяет рассматривать графы, в которых пару вершин может связывать несколько ребер (например, как-то по-разному помеченных).

¨ Дерево – это бинарное отношение (строгого) частичного порядка, дополнительно удовлетворяющее требованиям (иерархичности, древесности):

§ из того, что х<у,z следует, что у и z сравнимы, т.е. либо у£z либо z£у (х<у трактуется как: х встречается раньше у в пути к корню дерева, х – потомок, у - предок);

§ во множестве V (вершин дерева) существует наибольший элемент (корень дерева).

Деревья можно различать, если порядок сыновей (хотя бы для одной) вершины дерева различен. Упорядоченное дерево – дерево, в котором для каждой вершины задан порядок на множестве дочерних вершин, т.е. детей можно определить как первый, второй и т.д.

¨ Сеть – это отношение общего вида, которое можно трактовать как обобщение – E Í VÈV 2 È...V k , а можно – как отношение (E Í V k) с множеством элементов V, имеющим «пустой» (фиктивный) элемент.

Эти понятия, конечно, широко используются при разработке моделей задач предметных областей. Но также как и в случае множеств по ряду причин прагматического характера в программировании такое АТД общего (универсального) вида представляет ограниченный интерес. Точнее, разнообразные виды представления деревьев, графов и сетей, конечно, широко используются в практике программирования. Но совмещение их с универсальным набором операций и оформление такого универсального АТД представляется полезным только в простых ситуациях.

Фундаментальная роль деревьев и графов проявляется скорее в контексте прикладной задачи при выборе структур данных для эффективной реализации выбранных АТД и алгоритма решения задачи в целом. Но в таком контексте и их способ представления, и набор операций с этими деревьями, графами и сетями, естественно специализирован в соответствии с конкретным контекстом.

Абстрактный тип данных Общие положения о данных Абстрактный тип данных общие положения спецификация, представление, реализация 1

Что такое данные? Набор различных информационных объектов, над которыми выполняются те или иные действия операторами программы, называются данными. Данные - непременный атрибут любой программы. Ими могут быть: - отдельные биты; - последовательность независимых битов; -числа в разных формах представления; -байты и группы независимых байтов; -массивы чисел; -связные списки; -отдельные файлы и системы файлов. 2

Универсальное представление этого многообразия данных сложно и нецелесообразно Целесообразно разделить их на типы 3

Что такое тип данных? Тип данных определяется: – Форматом представления в памяти компьютера по определенным соглашениям алгоритмического языка, но без необходимости вычислений; – Множеством допустимых значений, которые может принимать принадлежащая к выбранному типу переменная или константа; – Множеством допустимых операций, применимых к этому типу. 4

Примеры типов данных Целочисленные типы Вещественный тип Логический тип Символьный тип Перечисляемый тип Интервальный тип Указатели 5

Целочисленные типы имеется пять предопределенных целочисленных типов: Shortint, Integer, Longint, Byte и Word. Каждый тип обозначает определенное подмножество целых чисел. Значение одного целочисленного типа может быть явным образом преобразовано к другому целочисленному типу с помощью приведения типов. 6

Вещественный тип К вещественному типу относится подмножество чисел, представляемых в формате с плавающей точкой и с фиксированным числом цифр. Запись значения в формате с плавающей запятой обычно включает три значения - m, b и e - таким образом, что m * b ^ e = n, где b всегда равен 2, а m и e являются целочисленными значениями в диапазоне вещественного типа. Эти значения m и e далее определяют диапазон представления и точность вещественного типа. Пример: 0. 143 E+22, где m - 0. 143; b=2(подразумевается), e=22. Имеется пять видов вещественных типов: вещественное (Real), с одинарной точностью (Single), с двойной точностью (Double), с повышенной точностью (Extended) и сложное (Comp). 7

Логический тип Существует 4 предопределенных логических (булевских) типа: Boolean, Byte. Bool, Word. Bool и Long. Bool. Значения булевского типа обозначаются встроенными идентификаторами констант False и True. Логические переменные могут использоваться для хранения результатов каких - либо логических вычислений. Для булевых переменных разрешены только 2 операции сравнения "="(равно) и ""(неравно). 8

Символьный тип Множеством значений этого типа являются символы, упорядоченные в соответствии с расширенным набором символов кода ASCII. Это буквы ["A". . . "Z", "a". . . "z"], цифры ["0". . . "9"], знаки препинания и специальные символы. Переменная этого типа в памяти занимает один байт. 9

Перечисляемый тип Перечислимые типы определяют упорядоченные множества значений через перечисление идентификаторов, которые обозначают эти значения. Упорядочение множеств выполняется в соответствии с последовательностью, в которой перечисляются идентификаторы. Type Week = (Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday); 10

Интервальный тип Интервальный тип представляет собой диапазон значений из порядкового типа. Определение интервального типа включает наименьшее и наибольшее значение в поддиапазоне. Type Interval = 0. . . 1000; Такая декларация типа указывает компилятору, что для переменных этого типа допустимы только числа из указанного диапазона. Тем самым в программе могут быть автоматически организованы проверки корректности операций присвоения для этих переменных. 11

Общее для типов данных Каждому из типов данных соответствует множество простых операций. INTEGER-операции +, -, *, div, mod REAL - операции + , -, *, / BOOLEAN- операции - конъюнкция (и), дизъюнкция V (или), отрицание (не) CHAR-операции ORD (с) -N: (С в ASCII), CHR (I) I -тый символ в ASCII По мере возрастания объемов и сложности представления информации возникает необходимость в удобных формах ее представления, хранения и обработки. 12

Определение абстрактный тип данных (АТД или abstract data type, или ADT), - это множество абстрактных объектов, представляющих элементы данных, и определенные на нем наборы операций, которые могут быть выполнены над элементами этого множества. 13

АТД – обобщение типов данных Абстрактные типы данных (АТД) можно рассматривать как средство расширения языков программирования. Сравним абстрактный тип данных с таким знакомым понятием, как процедура. Процедуру можно рассматривать как обобщённое понятие оператора. Две характерные особенности процедур – обобщение и инкапсуляция, отлично характеризуют абстрактные типы данных. АТД можно рассматривать как обобщение простых типов данных (целых, действительных и т. д.), точно также как процедура является обобщением простых операторов (+, - и т. д.) 14

Преимущества АТД Абстрактные структуры данных предназначены для удобного хранения и доступа к информации. Они предоставляют удобный интерфейс для типичных операций с хранимыми объектами, скрывая детали реализации от пользователя. Конечно, это весьма удобно и позволяет добиться большей модульности программы. 15

Пример Для автоматизированного управления температурой в различных комнатах большого здания полезным АТД был бы ТЕРМОСТАТ. В программе может быть много переменных типа ТЕРМОСТАТ, соответствующих реальным термостатам в различных помещениях здания. АТД может быть описан своим именем, множеством значений и допустимыми операциями так же, как и любой другой тип данных. Описание для типа ТЕРМОСТАТ: – Тип данных: ТЕРМОСТАТ – Область значений: температура может изменяться в диапазоне от 0 до 50 градусов (по Цельсию). – Операции: Выше, Ниже, Установить, Проверить, Тревога. (Можно придумать много полезных операций, но слишком большое их количество ухудшает абстракцию) 16

Уровни абстракции Уровни абстракции напоминают слои программного обеспечения. Высшие уровни абстракции отражают представление пользователя о решении задачи. Нижние уровни абстракции – возможности языка программирования. 17

Пример абстракции на уровне пользователя Архитектор представляет дом в виде стен, полов, окон, дверей и т. д. В этом случае тип данных Рисунок. Двери мог бы стать хорошим абстрактным типом. Тип данных: Рисунок. Двери Операции: Рисовать. Дверь Стереть. Дверь Рисовать. Двойную. Дверь ……. Рисунок. Двери являются абстракцией высокого уровня, отражающего взгляд пользователя на проблему 18

Пример абстракции на уровне программиста Программист может предложить другой уровень абстракции для этих объектов, например, прямоугольник. Тип данных: Прямоугольник Операции: Рисовать. Прямоугольник Стереть. Прямоугольник Разделить. Прямоугольник. На. Части ……. Прямоугольник – абстракция более низкого уровня, поскольку она ближе к реализации. 19

Конструкторы АТД Каждый АТД должен содержать операции построения значений своего типа. Такие операции называются конструкторами. Конструкторов должно быть достаточно для порождения всего множества значений данного типа. АТД, удовлетворяющий этому свойству, называется полным. Неполный АТД – ошибка проектирования. 20

Рекомендации к выбору операций абстрактного типа данных Целесообразно включение следующих операций: – операции-конструкторы, – операции проверки, – операции преобразования типов, – операции ввода-вывода, – операции копирования, – операции-селекторы. Постарайтесь свести к минимуму число операций. Простой АТД легче понять. Поддерживайте связь операций с выбранной абстракцией типа. 21

Первичный конструктор Операции, создающие новые значения АТД вне зависимости от его предшествующего значения, называются первичными конструкторами. Каждый АТД включает по меньшей мере один первичный конструктор: без него невозможно сформировать начальное значение. 22

Использование скрытых типов Абстрактные типы данных лучше объявлять в виде скрытых типов. Это позволяет переместить описание структуры данных в модуль реализации, где оно преимущественно используется. Они также обеспечивают возможность предотвращения прямого доступа к компонентам типа со стороны импортера. Поскольку скрытый тип всегда реализуется с помощью указателя, то в АТД должны быть включены три операции. – Создать - операция, создающая узел соответствующей структуры. – Уничтожить - операция по освобождению памяти узла скрытого типа. – Присвоить - операция копирования полей динамической структуры узла скрытого типа. 23

Что такое спецификация и реализация у абстрактного типа данных Абстрактный тип данных - это способ определения некоторого понятия в виде класса объектов с некоторыми свойствами и операциями. В языке программирования такое определение оформляется как специальная синтаксическая конструкция, называемая в разных языках капсулой, модулем, кластером, классом, пакетом, формой и т. д. Эта конструкция в самой развитой форме содержит: спецификацию типа данных, включающую описание интерфейса (имя определяемого типа, имена операций с указанием их профилей) и абстрактное описание операций и объектов, с которыми они работают, некоторыми средствами спецификации; реализацию типа данных, включающую конкретное описание тех же операций и объектов. 24

Классификация типов данных по способу описания и защиты пакетированный, если описание типа данных собрано в одном месте (в одном пакете), т. е. его объекты и операции объединены в одно понятие; он имеет определение, которое может содержать, однако, лишь его реализацию; инкапсулированный, если тип данных пакетированный, его определение содержит описание интерфейса и реализацию, а также предусмотрена инкапсуляция реализации; абстрактный, если тип данных инкапсулированный и его спецификация включает абстрактное описание. 25

Составляющие спецификации Программирование, как процесс, начинается с постановки задачи (ее определения), или спецификации задачи. Далее повсеместно в тексте используются спецификации, состоящие из шести составляющих: – Название - название решаемой задачи; – Описание - несколько предложений, описывающих суть задачи; – Вход - детальное описание предполагаемой формы входных данных; – Выход - детальное описание предполагаемой формы выходных данных; – Ошибки - подробный список ситуаций, возникающих при неправильных входных данных; – Пример - пример выполнения в терминах вход-выход. 26

П р и м е р спецификации Абстрактный тип данных СТЕК, реализующий широко известную структуру данных, которая характеризуется тем, что в нее можно "поместить" некоторый элемент и "выбрать" из нее элемент, помещенный туда самым последним. Синтаксическая часть спецификации типа данных СТЕК имеет вид type СТЕК specification is СОЗДАТЬ: function () return (@); ВСТАВИТЬ: function (integer; @) return (@); УДАЛИТЬ: function (@) return (@); ВЕРШИНА: function (@) return (integer); ПУСТ: function (@) return (boolean); end specification; Здесь операция СОЗДАТЬ выдает в качестве результата пустой стек, ВСТАВИТЬ - стек с добавленным на "верх" его элементом, УДАЛИТЬ - стек с удаленным "верхним" элементом, ВЕРШИНА - значение "верхнего" элемента стека, ПУСТ - признак пустоты стека. Элементами стека здесь могут быть только целые числа. 27

РЕАЛИЗАЦИЯ АБСТРАКТНОГО ТИПА ДАННЫХ Реализацию удобнее делать с помощью объектноориентированных языков программирования, таких как C++ или Java, в которых абстрактные типы данных поддерживаются с помощью классов Реализация АТД включает конкретное описание объектов определяемого типа и реализацию операций этого типа. Это означает, что объекты описываются либо как данные простых типов, либо как массивы, записи или объединения. Причем используются предопределенные типы данных или АТД, определенные ранее. Реализация операций состоит в описании подпрограмм, выполняющих необходимые действия с указанными объектами. Например операции +, *, =. . и т. п, но при этом скрывается сама реализация этих операций. 28

Доброго времени суток, хабравчане!

Следующий пост является изложением моих размышлений на тему природы классов и АТД. Эти размышления дополнены интересными цитатами из книг гуру разработки программного обеспечения

Введение

Начнем с того, что плавно подойдем к определению АТД. АТД, в первую очередь, представляет собой тип данных, что означет следущее:
наличие определенных доступных операций над элементами этого типа;
а также данные, относительно которых эти операции выполняются (диапазон значений).

Что же означает слово “абстрактный”? В первую очередь понятие “абстрактность” означет сосредоточение внимания на чем-то важном и, при этом, нам нужно отвлечься от неважных, на данный момент, деталей. Определение абстрактности хорошо раскрыто в книге Гради Буча (“Grady Booch”). Звучит определение так:

Абстракция – это выделение и придание совокупности объектов общих свойств, которые определяют их концепутальные границы и отличают от всех других видов объектов.
Иными словами, абстракция позволяет “пролить свет” на нужные нам данные объектов и, при этом, “затенить” те данные, которые нам не важны.

Итак, что же будет, если слить понятия “тип данных” и “абстракция” воедино? Мы получим тип данных, который предоставляет нам некий набор операций, обеспечивающих поведение объектов этого типа данных, а также этот тип данных будет скрывать те данные, с помощью которых реализовано данное поведение. Отсюда, приходим к понятию АТД:

АТД – это такой тип данных, который скрывает свою внутреннюю реализацию от клиентов.
Удивительно то, что путем применения абстракции АТД позволяет нам не задумываться над низкоуровневыми деталями реализации, а работать с высокоуровневой сущностью реального мира (Стив Макконнелл).

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

Преимущества АТД

Использование АТД имеет массу преимуществ (все описанные преимущества можно найти в книге Стива Макконнелла «Совершенный код”):

  • Инкапсуляция деталей реализации.
    Это означает, что единожды инкапсулировав детали реализации работы АТД мы предоставляем клиенту интерфейс, при помощи которого он может взаимодействовать с АТД. Изменив детали реализации, представление клиентов о работе АТД не изменится.
  • Снижение сложности.
    Путем абстрагирования от деталей реализации, мы сосредатачиваемся на интерфейсе, т.е на том, что может делать АТД, а не на том как это делается. Более того, АТД позволяет нам работать с сущностью реального мира.
  • Ограничение области использования данных.
    Используя АТД мы можем быть уверены, что данные, представляющие внутреннюю структуру АТД не будут зависеть от других участков кода. При этом реализуется “независимость” АТД.
  • Высокая информативность интерфейса.
    АТД позволяет представить весь интерфес в терминах сущностей предметной области, что, согласитесь, повышает удобочитаемость и информативность интерфейса.

Стив Макконнелл рекомендует представлять в виде АТД низкоуровнеые типы данных, такие как стек или список. Спросите себя, что представляет собой этот список. Если он представляет список сотрудников банка, то и рассматривайте АТД как список сотрудников банка.

Итак, мы разобрались, что такое АТД и назвали преимущества его применения. Теперь стоит отметить, что при разработке классов в ООП следует думать, в первую очередь, об АТД. При этом, как сказал Стив МакКоннелл, Вы программируете не на языке, а с помощью языка. Т.е Вы будете программировать выходя за рамки языка, не ограничиваясь мыслями в терминах массивов или простых типов данных. Вместо этого Вы будете думать на высоком уровне абстракции (например, в терминах электронных таблицах или списков сотрудников). Класс – это не что иное как дополнение и способ реализации концепции АТД. Мы можем даже представить класс в виде формулы:
Класс = АТД + Наследование + Полиморфизм.
Так почему же следут думать об АТД, при разработке классов. Потому что, сперва мы должны решить какие операции будут составлять интерфейс будущего класса, какие данные скрыть, а к каким предоставить открытый доступ. Мы должны подумать об обеспечении высокой информативности интерфейса, легкости оптимизации и проверки кода, а также о том, как бы нам предоставить правильную абстракцию, чтобы можно было думать о сущностях реального мира, а не о низкоуровнеых деталях реализации. Я считаю, что именно после определения АТД мы должны думать о вопросах наследования и полиморфизма.

Стоит отметить, что концепция АТД нашла гирокое применение в ООП, т.к именно эта концепция дополняет ООП и позволяет уменшить сложность программ в быстроменяющемся мире требований к ПО.

Данную статью я писал для того, что бы обратить внимание разработчиков на АТД с целью повышения качества работы и разработки программного обеспечения.

Использованные источники:

Стив Макконнелл – “Совершенный код”;
Роберт Седжвик – «Алгоритмы на Java».

1.2. Абстрактные типы данных

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

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

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

Определение абстрактного типа данных

Мы определяем абстрактный тип данных (АТД) как математическую модель с совокупностью операторов, определенных в рамках этой модели. Простым примером АТД могут служить множества целых чисел с операторами объединения, пересечения и разности множеств. В модели АТД операторы могут иметь операндами не только данные, определенные АТД, но и данные других типов: стандартных типов языка программирования или определенных в других АТД. Результат действия оператора также может иметь тип, отличный от определенных в данной модели АТД. Но мы предполагаем, что по крайней мене один операнд или результат любого оператора имеет тип данных, определенный в рассматриваемой модели АТД.

Две характерные особенности процедур - обобщение и инкапсуляция, - о которых говорилось выше, отлично характеризуют абстрактные типы данных. АТД можно рассматривать как обобщение простых типов данных (целых и действительных чисел и т.д.), точно так же, как процедура является обобщением простых операторов (+,- и т.д.). АТД инкапсулирует типы данных в том смысле, что определение типа и все операторы, выполняемые над данными этого типа, помещаются в один раздел программы. Если необходимо изменить реализацию АТД, мы знаем, где найти и что изменить в одном небольшом разделе программы, и можем быть уверенными, что это не приведет к ошибкам где-либо в программе при работе с этим типом данных. Более того, вне раздела с определением операторов АТД мы можем рассматривать типы АТД как первичные типы, так как объявление типов формально не связано с их реализацией. Но в этом случае могут возникнуть сложности, так как некоторые операторы могут инициироваться для более одного АТД и ссылки на эти операторы должны быть в разделах нескольких АТД.

Для иллюстрации основных идей, приводящих к созданию АТД, рассмотрим процедуру greedy из предыдущего раздела (листинг 1.3), которая использует простые операторы над данными абстрактного типа LIST (список целых чисел). Эти операторы должны выполнить над переменной newclr типа LIST следующие действия.

1. Сделать список пустым.

2. Выбрать первый элемент списка и, если список пустой, возвратить значение null.

3. Выбрать следующий элемент списка и возвратить значение null, если следующего элемента нет.

4. Вставить целое число в список.

Возможно применение различных структур данных, с помощью которых можно эффективно выполнить описанные действия. (Подробно структуры данных будут рассмотрены в теме 2.) Если в листинге 1.3 заменить соответствующие операторы выражениями

MAKENULL(newcJr);

w:= FIRST(newcJr);

w:= NEXT(newcfr);

INSERT(v, newclr);

то будет понятен один из основных аспектов (и преимуществ) абстрактных типов данных. Можно реализовать тип данных любым способом, а программы, использующие объекты этого типа, не зависят от способа реализации типа - за это отвечают процедуры, реализующие операторы для этого типа данных.

Вернемся к абстрактному типу данных GRAPH (Граф). Для объектов этого типа необходимы операторы, которые выполняют следующие действия.

1. Выбирают первую незакрашенную вершину.

2. Проверяют, существует ли ребро между двумя вершинами.

3. Помечают вершину цветом.

4. Выбирают следующую незакрашенную вершину.

Очевидно, что вне поля зрения процедуры greedy остаются и другие операторы, такие как вставка вершин и ребер в граф или помечающие все вершины графа как незакрашенные. Различные структуры данных, поддерживающие этот тип данных, будут рассмотрены в темах 6 и 7.

Необходимо особо подчеркнуть, что количество операторов, применяемых к объектам данной математической модели, не ограничено. Каждый набор операторов определяет отдельный АТД. Вот примеры операторов, которые можно определить для абстрактного типа данных SET (Множество).

1. MAKENULL(A), Эта процедура делает множество А пустым множеством.

2. UNION(A, В, С). Эта процедура имеет два "входных" аргумента, множества А и В, и присваивает объединение этих множеств "выходному" аргументу - множеству С.

3. SIZE(A). Эта функция имеет аргумент-множество А и возвращает объект целого типа, равный количеству элементов множества А. Термин реализация АТД подразумевает следующее: перевод в операторы языка программирования объявлений, определяющие переменные этого абстрактного типа данных, плюс процедуры для каждого оператора, выполняемого над объектами АТД. Реализация зависит от структуры данных, представляющих АТД. Каждая структура данных строится на основе базовых типов данных применяемого языка программирования, используя доступные в этом языке средства структурирования данных. Структуры массивов и записей - два важных средства структурирования данных, возможных в языке Pascal. Например, одной из возможных реализаций переменной S типа SET может служить массив, содержащий элементы множества S.

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

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



Понравилась статья? Поделиться с друзьями: