Лекции Программирование и основы алгоритмизации..

МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РФ
Федеральное государственное бюджетное образовательное
учреждение высшего профессионального образования
«Кузбасский государственный технический университет
имени Т.Ф. Горбачева»
Кафедра информационных
и автоматизированных производственных систем
Курс лекций по Дисциплине
Программирование
и основы алгоритмизации
Составил профессор кафедры,
д.т.н. Преслер В.Т.
Кемерово 2012

Оглавление
Введение в программирование и основа алгоритмизации 4
Тема 1. Программное средство. Исторический и социальный контексты программирования 6
1.1. Программа как формализованное описание процесса обработки данных. Программное средство 6
1.2. Понятие "правильной" программы 6
1.3. Надежность программного средства 7
1.4. Технология программирования как разработка надежных ПС 7
1.5. Информатизация общества 7
Тема 2. Источники ошибок в программных средствах 9
2.1. Интеллектуальные возможности человека 9
2.2. Неправильный перевод как причина ошибок в ПС 9
2.3. Модель перевода 10
2.4. Основные пути борьбы с ошибками 10
Тема 3. Общие принципы разработки программных средств 11
3.1. Специфика разработки ПС 11
3.2. Жизненный цикл ПС 11
3.3. Понятие качества ПС 12
3.4. Внешнего описания и его роль в обеспечении качества ПС 12
3.5. Обеспечение надежности – основной мотив разработки ПС 13
3.6. Борьба со сложностью систем и обеспечение точности перевода 14
Тема 4. Разработка структуры программы. Модульное и объектно-ориентированное
программирование 15
4.1. Цель модульного программирования 15
4.2. Основные характеристики программного модуля 15
4.3. Методы разработки структуры программы 16
4.4. Объектно-ориентированное программирование 18
4.5. События и событийная модель 22
Тема 5. Алгоритмизация и разработка программного модуля 24
5.1. Определение алгоритма 24
5.2. Изобразительные средства описания алгоритмов 24
5.3. Блок-схемы алгоритмов. Графические символы 25
5.4. Порядок разработки программного модуля 26
5.5. Структурное программирование 27
5.6. Пошаговая детализация и понятие о псевдокоде 28
Тема 6. Тестирование и отладка программного средства 30
6.1. Основные понятия 30
6.2. Принципы и виды отладки ПС 30
6.3. Заповеди отладки ПС 31
6.4. Автономная отладка ПС 31
Тема 7. Методы разработки алгоритмов 34
7.1. Метод частных целей 34
7.2. Метод подъема 35
7.3. Программирование с отходом назад 35
7.4. Алгоритмы ветвей и границ 38
Тема 8. Алгоритмы сортировки 43
8.1. Сортировка. Основные понятия 43
8.2. Пузырьковая сортировка 43
8.3. Сортировка с помощью дерева 44
8.4. Пирамидальная сортировка 45
8.5. Быстрая сортировка 47
Тема 9. Алгоритмы поиска и перебора 49
9.1. Поиск. Основные понятия 49
9.2. Бинарный поиск 49
9.3. Поиск в сети 50
9.4. Генератор перестановок 51
Тема 10. Событийно-управляемое программирование на языке Visual Basic 54
10.1. Историческая справка 54
10.2. Основы Visual Basic 55
10.3. Формы и элементы управления 57
10.4. Элементы управления пользователя 59
10.5. Фокус. Последовательность переходов. Меню 61
Тема 11. Управление проектами 64
11.1. Работа с проектом и его структура 64
11.2. Работа с несколькими проектами 65
11.3. Создание и запуск выполняемого файла. Компиляция 66
11.4. Установка параметров проекта 66
11.5. Дополнения и мастера 67
Тема 12. Управляющие конструкции 68
12.1. Конструкции принятия решения (ветвление) 68
12.2. Циклы 69
12.3. Работа со структурами управления и досрочный выход из них 70
Тема 13. Структура приложения. Техника написания кода 72
13.1. Структура приложения 72
13.2. Как работает событийное приложение 72
13.3. До начала кодирования 73
13.4. Техника написания кода 74
13.5. Автоматизация написания программы 75
Литература 76

Введение в программирование и основы алгоритмизации
Курс "Программирование и основы алгоритмизации" охватывает современные проблемные вопросы создания программных средств. Следует подчеркнуть – не просто программы, а программного средства определенной предметной области. Здесь выделяются два фундаментальных понятия программное средство и предметная область.
На заре информатики, когда она и наукой не считалась и таковой не являлась, основным результатом программирования была программа некоторой расчетной задачи, пусть и очень сложной, обеспечивавшая более быстрое по сравнению с ручным или механическим счетом получение результатов при разных входных данных. При этом ее эффективность полностью зависела от разработчика-программиста, насколько хорошо он уяснил, что и как должна делать программа, и насколько хорошо он владел методом решения задачи. Программа задачи разрабатывалась фактически с нуля, а изменение требований к ней приводило либо к значительному объему перепрограммирования, либо к разработке новой программы. Даже незначительное изменение условий задачи могло потребовать разработки новой программы, если прежний ее разработчик уже не работал в данной организации. Поскольку только у него в голове сидела модель программы, только он мог разобраться в ее исходном тексте, а документации, позволяющей стороннему человеку проникнуть в замысел, проект и конкретику реализации программы, просто не существовало.
Таким образом, создавались программы-однодневки, жившие ровно столько времени, сколько они были востребованы, или до очередных изменений требований к задаче, что происходило чрезвычайно часто в научно-исследовательском мире, ибо именно там, в первую очередь, вычислительная техника и программирование нашли широкое применение. Однако ущербность, хотя и вынужденная и необходимая, состоит не только в этом. Вместе с быстро умиравшими программами, человечество теряло гораздо больше, хотя и не осознавало что именно. Вместе с программами в небытие уходили талантливые прозрения (а первые программисты были исключительно талантливыми людьми), поскольку создававшийся в ходе программирования теоретический и практический багаж не становился общественным достоянием. Эти прозрения были, безусловно, и в области программирования (подходы к структурированию задач, приемы, процедурные наработки и их взаимодействие) и в предметной области (нестандартные подходы, методы и приемы решения задач).
Программистов увлекал сам процесс разработки программ, а не его анализ, теоретизация и обобщение в формах, доступных публикациям, а значит и восприятию другими специалистами не обязательно связанными с программированием. И в этом смысле программирование было искусством, но искусством одиночек, наслаждаться которым мог только сам разработчик. Расширение сфер применения вычислительной техники, а особенно ее проникновение в производственно-экономические области, привело к четкому осознанию обществом просто неограниченных возможностей и перспектив информатизации его сфер жизнедеятельности и тех общественных благ, которые она несет. Решение задач информатизации общества силами даже гениальных одиночек было просто немыслимо. Естественно, это осознание привело к изменению взгляда на программирование, потребовало всемерной интенсификации в области разработки программных продуктов, а значит и разработки научно-методических и технологических основ их "поточного" производства. Т.е. потребовался, осознанный обществом, переход от искусства одиночек к ремеслу многих.
И здесь возникают две взаимосвязанные сложнейшие проблемы, которые в форме понятий предметная область и программное средство были выделены в самом начале.
Во-первых, какую предметную область и как вычленить из многообразных и разнородных сфер информатизации. Во-вторых, какие задачи, для чего и кого, и как поставить в рамках этой предметной области, чтобы они были реализуемы, актуальны и востребованы в течение длительного периода в разнообразных процессах научной и производственно-экономической деятельности человека. И, в-третьих, как, каким образом, и какими средствами эти задачи реализовать в программном продукте, чтобы он был востребован на рынке услуг, окупился (необязательно в денежном эквиваленте) и внес вклад в сфере своего приложения. Следует особо отметить, что предметная область, вычленяемая как предмет информатизации (программирования) это, в первую очередь, виртуальная обобщенная модель процессов в некоторой сфере деятельности человека не тождественная реальным процессам в этой сфере. Естественно, чем больше уровень обобщения процессов в модели, тем шире границы предметной области, но сложнее и более длителен путь ее реализации и адаптации к реальным процессам. Уровень обобщения, срок и уровень сложности реализации и адаптации и должны определять границы предметной области, даже в том случае, когда ее в форме конкретных требований, условий и постановок задач строго очерчивает заказчик работ. Таким образом, предметная область – это только наше субъективное представление, модель-слепок реального мира, однако ее реализация в виртуальном не существующем в природе вещей программном продукте должна давать ощутимые реальные (действительные) результаты. Здесь четко проявляется следующая взаимосвязь событий, характерная для всех систем с обратной связью.
Действительность (мир предметов и вещей) ( Модель ( Программный продукт (виртуальное воплощение модели) ( Реальные результаты ( Адекватность модели или программного продукта ожидаемому результату ( Корректировка модели или модернизация программного продукта
Как следует из этого представления, неадекватность ожидаемому результату может быть как результатом несоответствия модели действительности, так и результатом несоответствия продукта самой модели этой действительности, а, возможно того и другого. Установить причину и тем более меру ответственности этапов моделирования и разработки программного продукта в этом несоответствии, особенно в больших системах, разрабатываемых большими коллективами, чрезвычайно трудно в отсутствии описания предметной области, документации модельных постановок задач, результатов их решения, требований спецификации по отдельным этапам разработки проекта. Отсюда неизбежно вытекает понятие программного средства, которое не сводится ни к предметной области, ни к программному продукту, а представляет собой нечто интегрирующее, обладающее свойствами исходных постановок (открытого начала), поэтапного детализированного обратимого проектирования и свойствами конечного продукта удовлетворять ожидаемые потребности. Под обратимым проектированием понимается способность локального и глобального возврата на предыдущие этапы с минимальной переработкой созданного материала (сохранение наработанного). В отличие от обычного предмета потребления программное средство не изнашивается (физически не стареет), но морально устаревает, однако благодаря открытому началу и обратимому проектированию может долго находиться на плаву за счет периодической модернизации и постоянного сопровождения.
По форме программное средство описывается простой формулой
Программы + Документация
Однако содержание гораздо богаче внешнего проявления (формы) поскольку включает:
коллективный и индивидуальный опыт разработки проектов, накапливаемый от проекта к проекту и используемый при разработке новых проектов,
опыт и приемы управления проектами, накапливаемый менеджерами и используемый для подбора, расстановки и обучения кадров и при дифференциации заданий по проектам и их совмещению во времени как в рамках отдельного проекта, так и в рамках нескольких, разрабатываемых одновременно проектов,
базы данных и базы знаний по разработке и управлению проектами, а также разнообразные программные средства по автоматизации процессов проектирования (разработки проектов), создаваемые в ходе работ над проектами.
Прежде чем перейти к изложению содержания курса "Технология программирования" хотел бы высказать свою точку зрения на алгоритмизацию задач. Современные процессы информатизации основываются на системном анализе, как предметной области, так и программ для решения ее задач, вытекающих из этого анализа. Рассмотрение программы как системы (даже малая цельная программа – это малая система) проявляет ее структуру в лице элементов и их взаимосвязей, причем сами элементы при этом могут также рассматриваться как системы и подвергаться дальнейшему структурному проявлению. Иерархическая структуризация программ, приводит в конечном итоге к вычленению условно-независимых структур-модулей. Такой подход позволяет полностью отказаться от разработки непрерывного алгоритма задачи, в котором все определено от начала до конца, и перейти к прерывистому, совмещенному во времени, программированию модулей даже в условиях нечетких постановок задач и не проработанности отдельных путей их решения. Таким образом, алгоритмизация, как процесс непрерывного упорядоченного выстраивания операций в программе, рассматриваемой как единое целое, теряет свое изначальное назначение и трансформируется в вычленение узловых точек-структур, связанных с определенными событиями либо с достаточно самостоятельными этапами решения задачи или ее подзадач, и установлению между ними информационных связей.
Тема 1
ПРОГРАММНОЕ СРЕДСТВО.
ИСТОРИЧЕСКИЙ И СОЦИАЛЬНЫЙ КОНТЕКСТЫ ПРОГРАММИРОВАНИЯ
1.1. Программа как формализованное описание процесса обработки данных.
Программное средство (ПС)
Целью программирования является описание процессов обработки данных, которые называются процессами. Данные ( это представление фактов и идей в формализованном виде, пригодном для передачи и обработки в некотором процессе. Информация ( это количественная и смысловая интерпретация данных при их представлении в процессах обработки. Обработка данных ( это выполнение систематической последовательности действий с данными. Данные представляются и хранятся на носителях данных. Совокупность этих носителей, используемая при обработке, называется информационной средой. Набор данных, содержащихся в некоторый момент в информационной среде, называется состоянием информационной среды. Процесс это последовательность сменяющихся состояний информационной среды. Задать процесс ( это определить последовательность ее состояний.
Чтобы заданный процесс порождался автоматически на компьютере, необходимо, чтобы его описание было формализовано. Формализация процесса на компьютере называется программированием, а результат формализации - программой. Для составления программ используются формализованные или формальные языки программирования (ФЯП). В отличие от исполняемого машинного кода компьютера формальные языки программирования существенно упрощают и ускоряют процесс разработки программ, делают программы читабельными и понятными не только разработчикам, но и квалифицированным пользователям. Программа, составленная на формальном языке программирования, переводится на машинный язык компьютера с помощью другой программы ( транслятора.
Процессу программирования предшествует подготовительный этап, включающий постановку задачи (задача выступает в роли процесса), выбор метода ее решения, спецификацию требований по организации и применению программы, а также другие вопросы. Информацию, полученную в ходе работы над задачей, необходимо фиксировать в виде отдельных документов. Эти документы часто не формализованы и рассчитаны на понятийное (смысловое) восприятие человеком. Программы разрабатываются в расчете на то, чтобы ими могли пользоваться люди, не участвующие в разработке, их то и называют пользователями. Для освоения программы пользователю требуется конкретная документация, поясняющая многообразные аспекты работы с ней, и очень редко сам текст программы.
Программа или логически связанная совокупность программ на носителях данных, снабженная программной документацией, называется программным средством (ПС). Если программа реализует некоторый процесс обработки данных на компьютере и создает эффект выполнения в виде результатов обработки, то программная документация разъясняет, регламентирует и интерпретирует этот процесс. В частности, определяет и интерпретирует функции, выполняемые программами ПС, разъясняет смысл исходных данных и процесс их подготовки, регламентирует запуск программ в работу и управление ими, интерпретирует получаемые результаты. Кроме того, программная документация позволяет разобраться в тексте программы, что необходимо, например, при ее модификации.
1.2. Понятие "правильной" программы
Продуктом технологии программирования (ТП) является программное средство, которое в рамках составляющих его программ выполняет возложенные на него задачи и функции. Здесь под программой часто понимают "правильную" программу, т.е. программу без ошибок. Однако понятие ошибки трактуется неоднозначно. Будем считать, что в программе имеется ошибка, если она не выполняет того, что разумно ожидать от нее пользователю. Разумное ожидание пользователя формируется на основании изучения неформальной программной документации. Следовательно, и понятие ошибки не формально. В ПС программы и документация взаимно увязаны, т.е. образуют некоторую общность. Поэтому правильнее говорить об ошибке в ПС. Будем считать, что в ПС имеется ошибка, если оно не отвечает разумному ожиданию пользователя. В частности, разновидностью ошибки является несогласованность между программами и документацией по их применению. Частным случаем ошибки является так называемый дефект программы, когда программа не соответствует своей функциональной спецификации, разрабатываемой на подготовительном этапе. Здесь следует иметь в виду, что причиной ошибки может оказаться сама функциональная спецификация, а не программа.
ВЫВОД. Так как задание на разработку программного средства неформально, вследствие чего и понятие ошибки не формализовано, то нельзя доказать математически (формальными методами) правильность ПС. Тестирование также не доказывает его правильность, а только демонстрирует наличие в нем ошибки. Поэтому понятие "правильной" программы неконструктивно, поскольку нет возможности доказать ее "правильность".
1.3. Надежность программного средства
Альтернативой "правильной" программы является надежное ПС. Надежность ПС ( это его способность безотказно выполнять определенные функции при заданных условиях в течение заданного периода времени с достаточно большой вероятностью. При этом под отказом в ПС понимают любое проявление в нем ошибки. Надежное ПС не исключает наличия ошибок ( важно, чтобы эти ошибки при практическом применении средства в заданных условиях проявлялись достаточно редко. Убедиться, что ПС обладает таким свойством, можно посредством тестирования, а также в ходе его эксплуатации. Таким образом, разрабатывать можно надежные, а не "правильные" ПС.
ПС обладает степенью надежности. Степень надежности характеризуется вероятностью работы без отказа в течение определенного периода времени. Однако в силу специфических особенностей ПС определить эту вероятность затруднительно по сравнению с решением этой задачи в технических отраслях знания. При оценке степени надежности следует учитывать последствия каждого отказа. Некоторые ошибки в ПС вызывают лишь отдельные неудобства в ходе эксплуатации, тогда как другие могут иметь катастрофические последствия, например, угрожать человеческой жизни. Поэтому для оценки надежности ПС иногда используют дополнительные показатели, учитывающие стоимость (вред) для пользователя каждого отказа.
1.4. Технология программирования как разработка надежных ПС
Под технологией программирования (ТП) понимается совокупность производственных процессов, приводящих к созданию ПС, а также описание этой совокупности процессов. В широком смысле - это технология разработки программных средств, включающая все процессы, начиная с момента зарождения идеи и кончая созданием программной документации. Каждый процесс этой совокупности базируется на использовании каких-либо методов и средств, например, компьютер. В этом случае говорят о компьютерной ТП. Близко к понятию ТП понятие программной инженерии, которая определяется как системный подход к разработке, эксплуатации, сопровождению и изъятию из обращения ПС. Главное различие между ТП и программной инженерией заключается в способе рассмотрения и систематизации материала. В ТП акцент делается на изучении процессов разработки ПС (технологических процессах) и порядке их прохождения. В программной инженерии изучаются методы и инструментальные средства разработки ПС, но с точки зрения достижения определенных целей.
ВЫВОД. В силу этих определений технология программирования концентрируется на изучении технологических процессов, приводящих к решению отдельной задачи или их взаимосвязанной совокупности, в то время как программная инженерия концентрируется на изучении общих методов и средств, определяющих жизненный цикл ПС с момента разработки до изъятия из обращения. В этом смысле программная инженерия и технология программирования соотносятся как общее и частное.
Следует различать технологию программирования и методологию программирования. В ТП методы рассматриваются с точки зрения организации технологических процессов - метод определяет технологию, а в методологии программирования - с точки зрения основ их построения, т.е. совокупности механизмов (программного инструментария), применяемых в процессе разработки программного обеспечения. Методология программирования отвечает на вопрос, как и посредством каких механизмов, программировать задачи, ТП - как создать надежное ПС и ввести его в эксплуатацию, а программная инженерия - как организовать и управлять жизненным циклом программ. В данном случае инженерия, технология и методология соотносятся как общее, особенное и частное. Поскольку надежность ПС является неотъемлемым его атрибутом, будем рассматривать ТП как технологию разработки надежных ПС. Это означает, что рассматривается весь процесс разработки ПС, начиная с возникновения замысла, в рамках которого изучаются вопросы построения программных конструкций, описания функций и принимаемых решений с точки зрения их неформального восприятия.
1.5. Информатизация общества
Технологии программирования играли разную роль на разных этапах развития информатики как науки. По мере повышения мощности компьютеров и развития методологии программирования росла и сложность решаемых на компьютерах задач, что, в свою очередь, потребовало повышенного внимания к технологии программирования. Резкое удешевление стоимости компьютеров и, в особенности, стоимости хранения информации на компьютерных носителях привело к широкому внедрению компьютеров практически во все сферы человеческой деятельности. Это кардинальное обстоятельство и определило направленность технологии программирования. Человеческий фактор стал играть в ней решающую роль. Сформировалось достаточно глубокое понятие качества ПС, причем предпочтение стало отдаваться не столько его эффективности, сколько удобству работы с ним пользователя. Широкое использование компьютерных сетей привело к интенсивному развитию распределенных вычислений, дистанционному доступу к информации и электронному способу обмена сообщениями между людьми. Компьютерная техника из средства решения отдельных задач все более превращается в средство информационного моделирования реального и мыслимого мира, способного отвечать людям на интересующие их вопросы. Начинается этап глубокой информатизации (компьютеризации) человеческого общества. Все это ставит перед ТП новые и достаточно трудные проблемы.
Краткий исторический экскурс.
50-е годы. Маломощные компьютеры. Программирование ведется в машинном коде. Решаются научно-технические задачи (расчеты по формулам), задание на программирование содержит достаточно точную постановку задачи. Используется интуитивная технология программирования: сразу приступают к составлению программы по заданию, при этом задание часто меняется, что увеличивает время ее составления, документация оформлялась после создания программы. В этот период родилась фундаментальная для технологии программирования концепция модульного программирования, преодолевшая трудности программирования в машинном коде. Появились языки программирования высокого уровня, из которых только язык ФОРТРАН пробился в следующие десятилетия.
60-е годы. Бурное развитие и широкое использование языков программирования высокого уровня (АЛГОЛ, ФОРТРАН, КОБОЛ и др.), значение которых явно преувеличивается. Надежда, что эти языки решат проблемы, возникающие в процессе разработки больших программ, не оправдались. Повышение мощности компьютеров и накопление опыта программирования приводило к росту сложности решаемых задач. В процессе решения этих задач обнаружилась ограниченность языков, проигнорировавших модульную организацию программ. И только ФОРТРАН, сохранивший возможность модульного программирования, прошествовал в следующие десятилетия. Его пользователи не могли отказаться от него из-за мощного фонда программных модулей. Четко осознается важность методологии и технологии программирования. Появление в компьютерах системы прерываний приводит к развитию мультипрограммирования и созданию больших программных систем. Широко используется коллективная разработка программ, поставившая ряд технологических проблем.
70-е годы. Широкое распространение информационных систем и баз данных. Стоимость хранения одного бита информации на компьютерных носителях стала меньше, чем на традиционных носителях. Повысился интерес к компьютерным системам хранения данных. Началось интенсивное развитие технологии программирования в следующих направлениях: 1) развитие нисходящей разработки и структурного программирования; 2) развитие абстрактных типов данных и модульного программирования, возникновение идеи разделения спецификации и реализации модулей и использование модулей, скрывающих структуры данных; 3) исследование проблем обеспечения надежности и мобильности ПС; 4) создание методики управления коллективной разработкой ПС; 5) разработка инструментальных ПС поддержки технологии программирования.
80-е годы. Внедрение персональных компьютеров во все сферы человеческой деятельности и создание обширного и разнообразного контингента пользователей ПС. Бурное развитие пользовательских интерфейсов и создание концепции качества ПС. Появление языков программирования, например, Ада, учитывающих требования технологии программирования. Развитие методов и языков спецификации ПС. Бурный процесс стандартизации технологических процессов и документации, создаваемой в них. Выход на передовые позиции объектного подхода к разработке ПС. Развитие инструментальных сред их разработки и сопровождения. Создание концепции компьютерных сетей.
90-е годы. Широкий охват человеческого общества международной компьютерной сетью, с подключением персональных компьютеров как терминалов. Это породило ряд проблем технологического, юридического и этического плана по регулированию доступа к информации. Возникла проблема защиты информации и передаваемых по сети сообщений. Бурно развивается компьютерная технология разработки ПС (CASE-технология) и связанные с ней формальные методы спецификации программ. Наступил решающий этап информатизации и компьютеризации общества.
Тема 2
ИСТОЧНИКИ ОШИБОК В ПРОГРАММНЫХ СРЕДСТВАХ
2.1. Интеллектуальные возможности человека
При разработке ПС используются три интеллектуальные способности человека: перебор, абстракция, математическая индукция.
Перебор это последовательное переключение внимания с одного предмета на другой и узнавание искомого предмета. Способность перебора ограничена – в среднем человек уверенно перебирает в пределах 1000 предметов. На практике человеку приходиться иметь дело с большим числом предметов. Средством преодоления этой ограниченности является способность к абстракции, благодаря которой человек объединяет разные предметы или экземпляры в одно понятие, заменяя множество элементов одним элементом другого рода. Способность человека к математической индукции позволяет справляться с бесконечными последовательностями.
При разработке ПС человек имеет дело с системами. Под системой понимают совокупность взаимодействующих друг с другом элементов. ПС – система. Логически связанный набор программ – система. Любая отдельная программа – система. Понять систему ( это осмысленно перебрать все пути взаимодействия между ее элементами. Различают простые и сложные системы. Простая система – система, в которой человек уверенно перебирает все пути взаимодействия между ее элементами, а сложная система – система, в которой он этого сделать не может. Между простыми и сложными системами нет четкой границы, поэтому вводится их промежуточный класс. К нему относятся программы, о которых программисты говорят «в каждой отлаженной программе имеется хотя бы одна ошибка».
При разработке ПС не всегда есть уверенность, что знаешь обо всех связях между его элементами. Часто невозможно отследить все связи, а это порождает поле возможных ошибок. Сложность системы оценивают числом ее элементов или числом потенциальных путей взаимодействия между элементами, т.е. n! (n-факториалом), где n ( число элементов системы. Систему называют малой, Сли n<7 (6!=720<1000), систему называют большой, если n>7. При n=7 имеем промежуточный класс систем. Малая система всегда проста, а большая может быть как простой, так и сложной. Задача технологии программирования ( научиться сводить большие системы к простым системам.
Оценка простых систем по числу элементов используется на практике. Так, для руководителя весьма желательно, чтобы в коллективе не было больше шести взаимодействующих между собой подчиненных. Важно следовать правилу: «все, что может быть сказано, должно быть сказано в шести пунктах или меньше». Этому правилу рекомендуется следовать при перечислении формулировок, взаимосвязанных высказываний, а также при разработке ПС.
2.2. Неправильный перевод как причина ошибок в ПС
При разработке и эксплуатации ПС неоднократно производится преобразование или перевод информации из одной формы в другую (рис.1). Заказчик формулирует свою потребность в ПС в виде требований. Исходя из них, разработчик создает внешнее описание ПС, используя спецификации необходимых аппаратных средств (аппаратуры) и базового программного обеспечения. Спецификация - это определение, описание и перечисление специфических особенностей. На основании внешнего описания и спецификации выбранного языка программирования создаются тексты программ. По внешнему описанию ПС разрабатывается и пользовательская документация. Текст каждой программы является исходной информацией при любом ее преобразовании, в частности, при исправлении в ней ошибок. Программная документация регламентирует действия пользователя по применению ПС и интерпретации результатов. Перевод информации имеет место и в других технологических процессах. На каждом из этих этапов перевод информации может быть осуществлен неверно, например, из-за неправильного понимания исходного представления информации. Возникнув на одном этапе, ошибка в представлении информации преобразуется в ошибки результатов, полученных на следующих этапах разработки, и, в конечном итоге, окажется в самом ПС.
2.3. Модель перевода
Чтобы понять природу ошибок рассмотрим самую общую модель перевода, изображенную на рис. 2. В ней отражен процесс перевода человеком информации из представления A в представление B. При этом он совершает четыре основных шага перевода: 1) получает информацию, содержащуюся в представлении A, с помощью читающего механизма R; 2) запоминает полученную информацию в памяти M; 3) выбирает из своей памяти преобразуемую информацию и информацию, описывающую процесс преобразования, выполняет перевод и посылает результат пишущему механизму W; 4) с помощью механизма W фиксирует представление B.
На каждом из этих шагов человек может совершить ошибку разной природы.
Во-первых, человек обладает способностью "читать между строк". Эта его особенность и способность, которая часто оказывается полезной, потому что позволяет ему понять текст, содержащий разного рода неточности или даже ошибки, в конечном итоге может стать причиной ошибки в ПС. Ошибка возникает в том случае, когда при чтении документа A человек пытается восстановить недостающую информацию, а необходимость в этом возникает довольно часто. При этом он видит то, что ожидает увидеть, а не то, что действительно имел в виду автор документа A. В такой ситуации оптимальным вариантом поведения является обращение к автору документа за разъяснениями.
Во-вторых, при запоминании информации человек осуществляет ее осмысливание и здесь важен его уровень подготовки и знание предметной области, к которой относится документ A. Если он поверхностно или неверно поймет содержание документа, то информация отложится в памяти в искаженном виде. Таким образом, сам процесс осмысления информации грешит ошибками.
В-третьих, забывчивость человека или неорганизованность его памяти может привести к тому, что он выберет из нее не всю преобразуемую информацию или не все правила перевода, в результате чего перевод будет осуществлен неверно. Это обычное явление и чаще всего происходит при большом объеме плохо организованной информации.
И, наконец, в-четвертых, известно извечное стремление человека как можно быстрее зафиксировать информацию, вопреки поговорке "семь раз измерь – один раз отрежь". Это естественное желание человека часто приводит к тому, что представление этой информации оказывается неточным, что и создает ситуации для последующей неоднозначной ее интерпретации.
2.4. Основные пути борьбы с ошибками
Учитывая рассмотренные особенности человеческой природы, играющие первостепенную роль при переводе, можно указать следующие пути борьбы с ошибками, вытекающих из этих особенностей:
сужение пространства перебора, или упрощение проектируемых систем,
обеспечение соответствующего уровня подготовки разработчика, что входит в функции менеджеров коллектива разработчиков,
обеспечение однозначности интерпретации представления информации,
контроль правильности перевода, включая и контроль однозначности интерпретации.

Тема 3
ОБЩИЕ ПРИНЦИПЫ РАЗРАБОТКИ ПРОГРАММНЫХ СРЕДСТВ
3.1. Специфика разработки ПС
Разработка ПС имеет ряд специфических особенностей.
Явное противоречие: неформальный характер требований к ПС в виде постановки задачи и понятие ошибки в нем, но формализованный, а, значит, формальный основной объект разработки ( программы. Таким образом, разработка программного средства содержит определенные этапы формализации, а переход от неформального описания задачи к формальному ее представлению на компьютере сугубо неформален.
Разработка ПС носит творческий характер, поскольку на каждом шаге разработки делается выбор, и принимаются соответствующие решения. Этот процесс не сводится к последовательности регламентированных действий. Разработка ПС ближе к процессу проектирования сложных устройств, чем к их массовому производству.
Продукт разработки является особенным. Он представляет собой совокупность текстов, т.е. статических объектов, а смысл (семантика) этих текстов выражается через процессы обработки данных и действия пользователей, запускающих эти процессы, т.е. является динамическим.
ПС при своем использовании не расходуется и не расходует используемых ресурсов, т.е. является виртуальным в отличие от физического продукта, создаваемого и используемого в процессах реального производства - потребляются ресурсы, и расходуется сам продукт.
3.2. Жизненный цикл ПС
Жизненный цикл ПС это весь период его разработки и эксплуатации, от момента возникновения замысла до прекращения его использования. Выделяют пять подходов по созданию и использованию ПС.
Водопадный подход. Разработка ПС сводится к последовательному выполнению цепочки этапов. На каждом этапе создаются документы, используемые на следующих этапах. В исходном документе фиксируются требования к ПС, а сами программы создаются в конце этой цепочки.
Исследовательское программирование. Подход предполагает быструю реализацию рабочих версий программ, которые приближенно выполняют требуемые функции, и создание минимальной документации по их применению. После апробации программ производится их модификация с целью адаптации к пользователю. Процесс повторяется, пока программы не будут полностью адаптированы. Подход применялся на ранних этапах развития программирования, когда использовалась интуитивная технология программирования. Сегодня этот подход применяется, когда пользователи не могут точно сформулировать требования, например, для систем искусственного интеллекта.
Прототипирование. Подход моделирует начальную фазу исследовательского программирования до создания рабочих версий программ, и предназначен для проведения экспериментов с целью установки требований к ПС. В дальнейшем следует разработка ПС по установленным требованиям в рамках другого подхода, например, водопадного.
Формальные преобразования. Подход включает разработку формальных спецификаций ПС и превращение их в программы путем корректных преобразований. На этом подходе базируется CASE-технология. Формальные преобразования лежат в основе моделирования сложных систем на базе их объектно-ориентированного анализа.
Сборочное программирование. ПС конструируется из компонент, которые уже существуют и хранятся в библиотеке компонент, каждая из которых может многократно использоваться в разных ПС. Такие компоненты называются повторно используемыми. Процесс разработки ПС сводится к сборке программ из этих компонент.
Рассматривать будем водопадный подход. Он в наибольшей мере охватывает класс технологических процессов, используемых для разработки ПС. В его рамках создаются большие программные системы. Он единственный рассматривается в качестве индустриального подхода к разработке программного обеспечения. В его рамках различают следующие стадии жизненного цикла ПС: разработку, производство программных изделий (ПИ) и эксплуатацию (рис. 3).
Стадия разработки ПС состоит из четырех этапов: внешнее описание, конструирование, кодирование (программирование в узком смысле) и аттестация. Всем этапам сопутствуют процессы документирования и управления ПС. Этапы конструирования и кодирования часто перекрываются, иногда сильно. Кодирование некоторых частей ПС может начинаться до завершения этапа конструирования.
Этап внешнего описания приводит к созданию документа, называемого внешним описанием ПС. Документ описывает поведения ПС с позиции внешнего наблюдателя и фиксирует требования относительно его качества. Внешнее описание начинается с анализа и определения требований к ПС со стороны пользователей (заказчика), и включает спецификацию этих требований.
Этап конструирования охватывает процессы разработки архитектуры ПС, структуризации его программ и их детальную спецификацию. Этап кодирования включает процессы создания текстов программ на языках программирования, их отладку и тестирование. На этапе аттестации производится оценка качества ПС. Если качество приемлемо, то разработка ПС считается законченной. Оформляется документ, фиксирующий результаты аттестации.
Программное изделие (ПИ) ( экземпляр или копия ПС. Изготовление ПИ ( это процесс генерации и/или воспроизведения (снятия копии) программ и программных документов с целью поставки пользователю. Производство ПИ ( это совокупность работ по изготовлению требуемого количества. Стадия производства ПИ вырожденная, рутинная, выполняемая автоматически и без ошибок.
Стадия эксплуатации охватывает хранение, внедрение и сопровождение ПС, транспортировку и применение ПИ по назначению. Состоит из параллельно проходящих фаз: применения, сопровождения. Применение ( использование ПС для решения задач на компьютере путем выполнения программ. Сопровождение ( сбор информации о качестве ПС при эксплуатации, устранение ошибок, доработка и модификация, а также извещение пользователей о внесенных изменениях.
3.3. Понятие качества ПС
Хорошее ПС должно обладать рядом свойств, обеспечивающих его использование в течение длительного периода, т.е. обладать определенным качеством. Качество ПС ( это совокупность черт и характеристик, которые определяют его способность удовлетворять заданные потребности пользователей. Совокупность свойств ПС, которые образуют удовлетворительное качество, зависят от условий и характера эксплуатации средства. Поэтому при описании качества должны быть зафиксированы критерии отбора требуемых свойств ПС. К критериям качества относятся: функциональность, надежность, легкость применения, эффективность, сопровождаемость, мобильность.
1. Функциональность ( это способность выполнять набор функций, удовлетворяющих потребности пользователя. Этот набор определяется во внешнем описании ПС.
2. Надежность обсуждалась в первой теме.
3. Легкость применения ( это характеристики и свойства, способствующие минимизации усилий пользователя по подготовке исходных данных, применению ПС и интерпретации результатов, а также вызывающие у него положительные эмоции.
4. Эффективность ( это отношение уровня услуг, предоставляемых ПС пользователю при заданных условиях, к объему используемых ресурсов.
5. Сопровождаемость ( это характеристики и свойства, способствующие минимизации усилий по внесению изменений в ПС и его модернизации.
6. Мобильность ( это способность ПС быть перенесенным из одной среды в другую, в частности, с одного компьютера на другой.
Функциональность и надежность – обязательные критерии качества, причем обеспечение надежности – главное требование на всех этапах и процессах разработки ПС. Остальные критерии используются в зависимости от потребностей пользователя.
3.4. Внешнего описания и его роль в обеспечении качества ПС
Разработка ПС начинается с процесса формулирования требований. Процесс основывается на пожеланиях заказчика и завершается созданием документа, определяющего задачи разработчиков. Этот документ называют внешним описанием ПС. Внешнее описание играет роль точной постановки задачи, решение которой обеспечивает создание ПС. Оно должно содержать информацию, необходимую пользователю для эксплуатации средства. Оно является исходным документом для трех параллельно протекающих процессов разработки текстов программ: конструирование и кодирование, разработка документации по применению, подготовка комплекта тестов.
Исходным документом для разработки внешнего описания является определение требований к ПС. Поскольку требования поступают от заказчика, то формирование документа представляет собой длительный и трудный итерационный процесс взаимодействия между заказчиком и разработчиком. Трудности связаны с тем, что пользователь плохо представляет, что ему нужно. Использование компьютера в "узких" местах деятельности пользователя может потребовать принципиального изменения всей технологии этой деятельности, о чем пользователь может не догадывается. Вопросы, которые необходимо отразить при определении требований, часто не имеют определенной формулировки, что приводит к неправильному пониманию разработчиком их сути. В связи с этим определению требований часто предшествует процесс системного анализа, в котором выясняется, насколько целесообразно и реализуемо "заказываемое" ПС, как повлияет оно на деятельность пользователя и какими особенностями оно должно обладать. Иногда разрабатывается упрощенная версия средства, называемая прототипом. Анализ "пробного" применения прототипа выявляет действительные потребности пользователя и уточняет требования к ПС.
Во внешнем описании выделяют две самостоятельные части - функциональную и нефункциональную спецификации. Функциональная спецификация описывает функции, которые должно выполнять ПС, и, следовательно, определяет фрагменты программ, реализующие декларированные функции. Нефункциональная спецификация определяет требования к качеству ПС, которые формулируются так, чтобы были ясны цели, которые необходимо достичь в ходе разработки. Иначе эту часть внешнего описания называют спецификацией качества. Спецификация качества, в отличие от функциональной спецификации, представляется в неформализованном виде и определяет выбор альтернативных решений при реализации функций ПС, а также стиль документов и программ. Разработка спецификации качества предшествует разработке функциональной спецификации, так как некоторые требования к качеству предопределяют включение в функциональную спецификацию специальных функций, например, защиты от несанкционированного доступа к объектам информационной среды. Структуру внешнего описания выражает формула
Внешнее описание ПС =
определение требований + спецификация качества + функциональная спецификация
Внешнее описание определяет, что должно делать ПС и какими внешними свойствами обладать. Оно не указывает, как обеспечить эти внешние свойства и как организовать ПС. Внешнее описание должно точно и полно определить те задачи, которые будут решать разработчики ПС. В то же время оно должно быть понятно заказчику, так как на его основании принимается решение о заключении договора на разработку ПС. Внешнее описание играет ключевую роль и в обеспечении качества ПС, так как спецификация качества ставит перед разработчиком конкретные ориентиры, определяющие решения для реализации специфицированных функций.
3.5. Обеспечение надежности – основной мотив разработки ПС
Известны четыре подхода к обеспечению надежности ПС: предупреждение, самообнаружение, самоисправление, обеспечение устойчивости к ошибкам.
Предупреждения ошибок ( не допустить их в ПС. Достижение этого лежит на пути решения следующих задач: преодоление сложности, точность перевода, преодоление барьера между пользователем и разработчиком, контроль принимаемых решений. Предупреждение ошибок связано с организацией процессов разработки ПС. И хотя гарантировать отсутствие ошибок невозможно, в рамках этого подхода можно достичь приемлемый уровень надежности ПС.
Остальные три подхода связаны с организацией программ. Они учитывают возможность возникновения ошибок в них. Самообнаружение ошибки означает, что программа содержит средства обнаружения отказов в процессе своего выполнения. Самоисправление ошибки означает не только обнаружение отказа в процессе выполнения программы, но и исправление последствий этого отказа, для чего в программе предусматриваются соответствующие средства. Обеспечение устойчивости к ошибкам означает, что в программе содержатся средства, локализующие область влияния отказа, либо уменьшающие его неприятные последствия, а иногда и предотвращающие последствия отказа. Эти три подхода используются редко. Чаще используется обеспечение устойчивости к ошибкам. Связано это, во-первых, с тем, что простые методы, используемые в технике, в рамках этих подходов неприменимы в программировании, например, дублирование отдельных блоков и устройств. Выполнение двух копий одной и той же программы всегда будет приводить к одинаковому эффекту. Во-вторых, добавление в программу дополнительных фрагментов приводит к ее усложнению, что затрудняет работу методов предупреждения ошибок.
3.5. Борьба со сложностью систем и обеспечение точности перевода
Известны два метода: обеспечение независимости компонент, использование иерархических структур.
Обеспечение независимости компонент означает разбиение системы на части с минимальным числом связей. Одно из воплощений этого метода – модульное программирование. Использование в системах иерархических структур локализует связи между компонентами, допуская их лишь между компонентами, принадлежащим смежным уровням иерархии. Этот метод означает разбиение большой системы на малые подсистемы. Здесь используется способность человека к абстрагированию.
Обеспечение точности перевода направлено на достижение однозначности интерпретации документов различными разработчиками, а также пользователями ПС. Это требует придерживаться при переводе определенной дисциплины. Используется общая дисциплина решения задач, которая рассматривает перевод как решение некоторой задачи. В соответствии с этим весь процесс перевода разбивается на этапы: 1) уяснение задачи, 2) составление плана, включающего цели и методы решения, 3) выполнение плана, проверка правильности каждого шага, 4) анализ полученного решения, 5) если решение не удовлетворяет, возврат к уяснению задачи.
Чтобы обеспечить разумное ожидание пользователя от ПС разработчикам необходимо понять, чего хочет пользователь, каков уровень его подготовки и какова окружающая его обстановка. Ясное описание сферы деятельности пользователя или интересующей его проблемной области облегчает достижение этой цели. При разработке ПС следует привлекать пользователя к участию в процессах принятия решений, а также изучить особенности его работы.

Тема 4
РАЗРАБОТКА СТРУКТУРЫ ПРОГРАММЫ.
МОДУЛЬНОЕ и объектно-ориентированное ПРОГРАММИРОВАНИЕ
4.1. Цель модульного программирования
Программа - большая система, поэтому необходимы меры для ее упрощения. Программу разбивают и разрабатывают по частям. Эти части называются программными модулями, а метод разработки программ - модульным программированием. Программный модуль ( это фрагмент описания процесса, оформляемый как самостоятельный программный продукт. Это означает, что каждый программный модуль программируется, компилируется и отлаживается отдельно от других модулей. Так процесс разработки программы физически разделяется. Разработанный модуль может включаться в состав разных программ, если выполнены условия его использования. Модуль рассматривается и как средство борьбы со сложностью, и как средство борьбы с дублированием в программировании, т.е. как средство накопления и многократного использования программистских знаний.
Модульное программирование - общий метод борьбы со сложностью. Оно обеспечивает независимость разработки отдельных компонент системы с опорой на иерархические структуры программирования. Для обеспечения этой независимости формулируются требования, которым должен удовлетворять модуль. Для этого выявляются основные характеристики "хорошего" модуля.
4.2. Основные характеристики программного модуля
Выделить "хороший" модуль - сложная задача. Неформально приемлемость модуля оценивается так: 1) хороший модуль снаружи проще, чем внутри, 2) хороший модуль проще использовать, чем построить. Для оценки приемлемости модуля используются более конструктивные характеристики: размер модуля, прочность модуля, сцепление с другими модулями, рутинность модуля (независимость от предыстории обращений к нему).
1. Размер модуля определяется числом содержащихся в нем операторов или строк. Модуль должен быть не малым и не большим. Маленькие модули приводят к громоздкой структуре программы и не окупают расходов, связанных с их оформлением. Большие модули неудобны для изучения и изменения. Рекомендуются модули от нескольких десятков до нескольких сотен операторов.
2. Прочность модуля ( это мера его внутренних связей. Чем выше прочность модуля, тем больше связей он может спрятать от внешней по отношению к нему программы и тем больший вклад в упрощение программы он внесет. Для оценки степени прочности используется упорядоченный набор классов модулей. Самой слабой степенью прочности обладает модуль, прочный по совпадению. Это модуль, между элементами которого нет осмысленных связей. Такой модуль выделяется при обнаружении в разных местах программы повторения одной и той же последовательности операторов. Изменение этой последовательности в одном месте приводит к изменению самого модуля, что делает его использование в других местах ошибочным. Этот класс модулей не рекомендуется использовать. Из остальных к использованию рекомендуются только два высших класса. Рассмотрим эти классы.
1) Функционально прочный модуль ( это модуль, выполняющий одну определенную функцию. Такой модуль могут использовать и другие модули.
2) Информационно прочный модуль ( это модуль, выполняющий несколько операций (функций) над одной и той же структурой данных или информационными объектами, которые считается неизвестными вне рамок модуля. Для каждой из этих операций в модуле имеется свой вход со своей формой обращения к нему. Этот класс модулей обладает высшей степенью прочности. Информационно прочный модуль реализует, например, абстрактный тип данных.
3. Сцепление модуля ( это мера его зависимости по данным от других модулей. Сцепление характеризуется способом передачи данных. Чем слабее сцепление модуля, тем сильнее его независимость. Для оценки степени сцепления используется упорядоченный набор видов сцепления. Худшим видом является сцепление по содержимому. Таким является сцепление двух модулей, когда один из них имеет прямые ссылки на содержимое другого модуля, например, его константу. Такое сцепление недопустимо. Не рекомендуется использовать также сцепление по общей области, когда несколько модулей используют одну и ту же область памяти. Такое сцепление реализовано, например, в языке ФОРТРАН в форме блоков COMMON. Единственным видом сцепления модулей, который рекомендуется для использования, является параметрическое сцепление, когда данные передаются модулю при обращении к нему как значения его параметров, или как результат его обращения к другому модулю для вычисления некоторой функции. Такой вид сцепления модулей реализован в языках программирования, использующих обращения к процедурам (функциям).
4. Рутинность модуля ( это его независимость от предыстории обращений к нему. Модуль называется рутинным, если результат (эффект) обращения к нему зависит только от значений его параметров. Модуль называется зависящим от предыстории, если результат обращения к нему зависит от его внутреннего состояния, изменяемого в результате предыдущих обращений. Такие модули могут провоцировать появление в программах неуловимых ошибок. Однако во многих случаях зависящий от предыстории модуль является лучшей реализаций информационно прочного модуля. Следует использовать рутинный модуль, если это не приводит к плохим сцеплениям модулей. Зависящие от предыстории модули следует использовать в случае, когда это необходимо для обеспечения параметрического сцепления. При этом в спецификации модуля необходимо формулировать эту зависимость, чтобы прогнозировать его поведение при последующих обращениях к нему.
4.3. Методы разработки структуры программы
В качестве модульной структуры программы используют древовидную структуру. В узлах такого дерева размещаются программные модули, а направленные дуги (стрелки) описывают статическую подчиненность модулей. Каждая дуга показывает, что в тексте модуля, из которого она исходит, имеется ссылка на модуль, в который она входит. Модульная структура программы обязана включать и совокупность спецификаций модулей, ее образующих. Спецификация модуля содержит: 1) спецификацию его входов, позволяющую строить на языке программирования синтаксически корректное обращение к нему или к его входам; 2) функциональную спецификацию, содержащую описание семантики функций, выполняемых модулем по каждому из его входов. Функциональная спецификация модуля строится так же, как и функциональная спецификация ПС.
Различают два метода разработки модульной структуры программы: восходящая и нисходящая разработка.
1. Метод восходящей разработки. Строится модульная структура программы в виде дерева. Затем модули поочередно программируются, начиная с модулей нижнего уровня. Программирование проводится в таком порядке, чтобы для программируемого модуля ранее были запрограммированы те модули, к которым он обращается. Когда модули запрограммированы, производится их поочередное тестирование и отладка в таком же восходящем порядке. Такой порядок естественен, так как каждый модуль выражается через уже запрограммированные подчиненные ему модули, а при тестировании используются уже отлаженные модули. Однако этот порядок разработки не рекомендуется. Во-первых, для программирования модуля не требуется наличия текстов используемых им модулей. Достаточно, чтобы используемый модуль был специфицирован в объеме, позволяющем построить корректное обращение к нему, а для тестирования использовать имитатор (заглушку) этого модуля. Во-вторых, каждая программа подчиняется некоторым внутренним для нее, но глобальным для ее модулей принципам реализации, предположениям, структурам данных и т.п., что и определяет ее концептуальную целостность и направляет процесс разработки. При восходящей разработке эта глобальная концепция для модулей нижних уровней еще не проработана, поэтому приходится отдельные модули перепрограммировать, когда при программировании других модулей производится уточнение этой концепции, например, изменяется глобальная структура данных. В-третьих, при восходящем тестировании для каждого модуля, кроме головного, приходится создавать ведущий модуль, который готовит для тестируемого модуля необходимое состояние информационной среды и производит обращение к нему. Это увеличивает объем "отладочного" программирования и не дает гарантий соответствия условий тестирования реальным условиям применения программы.
2. Метод нисходящей разработки. Как и ранее строится модульная структура программы в виде дерева. Затем поочередно программируются модули, начиная с верхнего уровня, головного модуля, переходя к программированию очередного модуля только тогда, когда запрограммирован модуль, к нему обращающийся. Когда модули запрограммированы, производится их поочередное тестирование и отладка в том же нисходящем порядке. Первым тестируется головной модуль, представляющий всю программу. Он тестируется при "естественном" состоянии информационной среды, определяющей начальное состояние программы. Модули, к которым обращается головной, заменяются имитаторами-заглушками. Имитатор модуля - это программный фрагмент, который сигнализирует о факте обращения к модулю. Он производит обработку значений его входных параметров, например, распечатывает эти значения, и выдает заранее запасенный результат. После завершения тестирования и отладки головного и любого последующего модуля производится переход к тестированию модуля, ранее представленного имитатором. Имитатор заменяется самим модулем, и добавляются имитаторы тех модулей, к которым он обращается. Модуль тестируется при "естественном" состоянии информационной среды, возникшей к моменту обращения к нему. Большой объем "отладочного" программирования при восходящем тестировании заменяется программированием простых имитаторов модулей. При таком порядке разработки информационная среда формируется своевременно. Недостатком нисходящей разработки является необходимость абстрагироваться от базовых возможностей языка программирования, применяя абстрактные операции, которые позже нужно будет реализовать посредством тех же модулей.
Особенностью двух рассмотренных классических методов разработки является наличие модульной структуры программы до начала программирования. Это требование находится в полном соответствии с водопадным подходом, так как разработка структуры программы и ее кодирование производятся на разных этапах разработки. Разработка модульной структуры завершает этап конструирования, а непосредственно программирование ( открывает этап кодирования. Если в теоретическом плане классические методы не вызывают возражений, то на практике их реализация сталкивается с рядом трудностей, связанных с тем, что до программирования невозможно точно и содержательно разработать саму структуру программы. Эти затруднения снимаются в рамках конструктивного и архитектурного подходов, модернизирующих водопадный подход и совмещающих процессы модульной структуризации и программирования.
3. Конструктивный подход - это модификация нисходящей разработки, в которой структура программы формируется в процессе программирования модулей. Разработка программы начинается с головного модуля, исходя из спецификации программы в целом. Она принимается в качестве спецификации ее головного модуля, который берет на себя ответственность за выполнение функций программы в целом. В процессе его программирования выделяются подзадачи (внутренние функции). Это означает, что для выделенной подзадачи-функции создается спецификация фрагмента программы. Фрагмент в дальнейшем может быть представлен некоторым поддеревом модулей. Ответственность за выполнение выделенной функции несет головной модуль этого поддерева. Спецификация этой функции является одновременно и спецификацией головного модуля этого поддерева. В головном модуле программы для обращения к выделенной функции строится обращение к головному модулю указанного поддерева. На первом шаге разработки программы (ее головного модуля) формируется верхняя начальная часть дерева согласно рис. 7. Аналогичные действия производятся при программировании любого другого модуля, который выбирается из числа уже специфицированных модулей. В результате этого производится очередная достройка дерева программы, например, согласно рис. 8.
13 SHAPE \* MERGEFORMAT 1415
4. Архитектурный подход - это модификация восходящей разработки, при которой модульная структура программы формируется в процессе программирования. Его целью является не разработка конкретной программы, а повышение уровня использования языка программирования. Это означает, что для данной предметной области выделяются типичные функции, которые могут использоваться при решении разных задач этой области. Эти функции специфицируются, а затем программируются модули, их реализующие. Процесс выделения функций связан с опытом решения задач в предметной области, поэтому сначала выделяются и реализуются простые функции, а затем программируются модули, реализующие более сложные функции с использованием запрограммированных простых функций. Так создается набор модулей в расчете на его применение в программах предметной области. Этот подход сокращает трудозатраты на разработку программы путем подключения заранее заготовленных и проверенных на практике структур нижнего уровня. Такие структуры (модули) могут многократно использоваться в разных программах, поэтому архитектурный подход рассматривается как средство борьбы с дублированием в программировании.
5. Метод нисходящей реализации. В методе нисходящей разработки рекомендуется сначала все модули запрограммировать, а затем провести их нисходящее тестирование. Такой порядок разработки неэффективен. Тестирование и отладка модулей может приводить к изменению спецификации подчиненных модулей и даже к изменению модульной структуры программы, в этом случае программирование некоторых модулей окажется бесполезной работой. Рационален порядок разработки, модифицирующий водопадный подход, и известный как метод нисходящей реализации. В данном методе каждый запрограммированный модуль тестируют сразу же после своего программирования до перехода к программированию другого модуля.
Методы имеют разновидности, зависящие от порядка обхода узлов-модулей древовидной структуры программы. Например, в лексикографическом порядке - сверху вниз или слева направо. Или обход по слоям. Сначала разрабатываются модули одного уровня, а затем следующего.
6. Метод целенаправленной конструктивной реализации. При конструктивной реализации используется метод вертикального слоения Фуксмана, суть которого в следующем. В рамках конструктивного подхода реализуются модули, которые необходимы для простейшего варианта программы, функционирующей для ограниченного набора входных данных. Вместо других модулей, на которые имеются ссылки, используются имитаторы. Затем к программе вместо имитаторов добавляются реализации модулей, обеспечивающие выполнение программы для других наборов входных данных. Процесс продолжается поэтапно до полной реализации программы. В этом методе обход дерева программы производится по кратчайшему пути, реализующему последовательно наращиваемые варианты функционирующей программы, начиная с самого простого. Такая разновидность конструктивной реализации получила название метода целенаправленной конструктивной реализации. Достоинство метода - уже на ранней стадии создается работающий вариант программы. Психологически это играет роль допинга, повышающего эффективность разработчика. Метод перспективен.
Классификация методов разработки структуры программы
13 SHAPE \* MERGEFORMAT 1415
4.4. Объектно-ориентированное программирование
Объектно-ориентированное, или объектное программирование (в дальнейшем ООП) – парадигма программирования, в которой основными концепциями являются понятия объектов и классов. ООП возникло в результате развития идеологии процедурного программирования, где данные и подпрограммы (процедуры, функции) их обработки формально не связаны. Для дальнейшего развития ООП большое значение имеют понятия события (так называемое событийно-ориентированное программирование) и компонента (компонентное программирование, КОП).
Формирование КОП от ООП, как и модульного программирования, произошло от процедурного программирования: процедуры сформировались в модули (независимые части кода на уровне сборки программы), а объекты сформировались в компоненты (независимые части кода на уровне выполнения программы). Взаимодействие объектов происходит посредством сообщений. Результатом дальнейшего развития ООП, по-видимому, будет агентно-ориентированое программирование, где агенты независимые части кода на уровне выполнения. Взаимодействие агентов происходит посредством изменения среды, в которой они находятся.
Первым языком ООП стала Симула (1967 г.). В нем были реализованы поистине революционные идеи: объекты, классы, виртуальные методы и др. Однако эти идеи не были восприняты современниками. Большинство концепций ООП были развиты А. Кейем и Д. Ингаллсом в языке Smalltalk. Он стал первым широко распространённым языком ООП. В настоящее время количество прикладных языков, реализующих парадигму ООП, является наибольшим по отношению к другим парадигмам. В области системного программирования до сих пор применяется процедурное программирование, которое ведется на языке C. Хотя и здесь заметно влияние языков ООП. Так одной из наиболее распространенных библиотек мультиплатформенного программирования является объектно-ориентированная библиотека Qt, разработанная на C++.
Основные понятия ООП
К основным понятиям ООП относятся: объект, класс, прототип, абстракция, инкапсуляция, наследование, полиморфизм.
Объект – сущность в адресном пространстве вычислительной системы, появляющаяся при создании экземпляра класса или копировании прототипа, например, после запуска результатов компиляции и связывания исходного кода для выполнения. Это центральное понятие ООП. Объект может посылать сообщения, принимать и реагировать на них, используя свои данные.
Класс является моделью ещё не существующей сущности (объекта), описываемой на языке терминологии исходного кода (пространство имён). Фактически класс описывает устройство объекта, является своего рода его чертежом. Говорят, что объект – это экземпляр класса. Обычно классы разрабатывают таким образом, чтобы их объекты соответствовали объектам предметной области.
Прототип – объект, по образу и подобию которого создаются другие объекты. Созданные объекты могут сохранять связь с родительским объектом, автоматически наследуя изменения в прототипе; эта особенность определяется в рамках конкретного языка. Прототип – альтернативное классам понятие (реализован в языке Self).
Абстрагирование – способ выделения значимых характеристик объекта из множества присущих ему. Соответственно абстракция – это набор выделенных характеристик.
Инкапсуляция – свойство системы, позволяющее объединить в классе данные и методы, работающие с ними, и скрывать детали их реализации от пользователя.
Наследование – свойство системы, позволяющее описать новый класс на основе уже существующего с частичной или полностью заимствованной функциональностью. Класс, от которого производится наследование, называется базовым, родительским или суперклассом. Новый класс – потомком, наследником или производным классом.
Полиморфизм – свойство системы использовать объекты с одинаковым интерфейсом без знания типа и внутренней структуры объекта.
Наличие инкапсуляции, наследования и полиморфизма являются необходимыми и достаточными условиями объектной ориентированности языка программирования.
Определение ООП и его основные концепции
ООП насчитывает более чем сорокалетнюю историю, но до сих пор не существует общепринятого определения данной технологии. Принципы, заложенные в первые объектные языки и системы, подверглись существенному изменению и дополнению в ходе реализации последующие времена. С середины 1980-х годов термин «объектно-ориентированный» стал модным, в результате его стали «прикреплять» к любым новым разработкам, чтобы обеспечить их привлекательность.
Суть ООП. По мнению Кея (один из основателей ООП), объектно-ориентированный подход заключается в следующем. Всё является объектом. Вычисления осуществляются путём взаимодействия (обмена данными) объектов, в котором один объект требует от другого выполнения некоторого действия. Объекты взаимодействуют, посылая и получая сообщения. Сообщение – это запрос на выполнение действия, дополненный набором аргументов, которые могут понадобиться при его выполнении. Каждый объект имеет независимую память, которая состоит из других объектов. Каждый объект является представителем (экземпляром) класса, который выражает общие свойства объектов. В классе задаётся поведение (функциональность) объекта. Тем самым все объекты, которые являются экземплярами одного класса, могут выполнять одни и те же действия. Классы организованы в единую древовидную структуру с общим корнем, называемую иерархией наследования. Память и поведение, связанное с экземплярами определённого класса, автоматически доступны любому классу, расположенному ниже в иерархическом дереве. Таким образом, программа представляет собой набор объектов, имеющих состояние и поведение. Объекты взаимодействуют посредством сообщений. Иерархия объектов выстраивается естественным образом. Программа в целом – объект, который для выполнения своих функций обращается к входящим в неё объектам, которые, в свою очередь, выполняют запрошенное действие путём обращения к другим объектам программы. Естественно, чтобы избежать бесконечной рекурсии в обращениях, на каком-то этапе объект трансформирует обращённое к нему сообщение в сообщения к стандартным системным объектам, предоставляемым средой программирования. Устойчивость и управляемость системы обеспечивается за счёт чёткого разделения ответственности объектов, однозначного определения интерфейсов межобъектного взаимодействия и полной изолированности внутренней структуры объекта от внешней среды.
Иерархия классов. Появление в ООП понятия класса обусловлено, необходимостью иметь множество объектов со сходным поведением. Класс в ООП – абстрактный тип данных, создаваемый программистом. Объекты являются значениями данного абстрактного типа, а определение класса задаёт внутреннюю структуру значений и набор операций, которые над ними могут выполняться. Необходимость иерархии классов (наследования) вытекает из требования повторного использования кода. Если классы имеют сходное поведение, нет смысла дублировать их описание, лучше выделить общую часть в общий родительский класс, а в описании самих классов оставить только различающиеся элементы.
Поддержка полиморфизма. Необходимость совместного использования объектов разных классов, способных обрабатывать однотипные сообщения, требует поддержки полиморфизма – возможности записывать разные объекты в переменные одного и того же типа. При этом объект, отправляя сообщение, может не знать, какому классу принадлежит адресат. Одни и те же сообщения, отправленные переменным одного типа, содержащим объекты разных классов, вызовут различную реакцию. Концепция обмена сообщениями реализуется посредством вызовов доступных извне методов. Данный подход использован в таких языках как C++, Object Pascal, Java, Oberon-2.
Наследование. Объект является значением, относящимся к определённому классу. Класс представляет собой составной тип данных, имеющий в составе: 1) поля данных – параметры, задающие состояние иначе свойства объекта; 2) методы – процедуры и функции, определяющие действия над объектом данного типа, которые объект может выполнять. В силу свойства наследования класс-потомок получает все свойства и методы класса-родителя, но может дополнить их собственными свойствами, или переопределить имеющиеся. В основном поддерживается только единичное наследование. Класс может иметь только одного родителя. Множественное наследование – порождение класса от двух и более родителей из-за сложности реализации практически не используется. Вместо него используется понятие интерфейса. Интерфейс – это класс без полей и без реализации, включающий только заголовки методов. Если некий класс наследует интерфейс, он должен реализовать все входящие в него методы. Использование интерфейсов – относительно дешёвая альтернатива множественному наследованию.
Инкапсуляция. Обеспечивается посредством контроля и методов доступа. Методы класса могут быть как чисто внутренними, обеспечивающими логику функционирования объекта, так и внешними, с помощью которых взаимодействуют объекты, необходимо обеспечить скрытость первых при доступности извне вторых. Для этого в языки вводятся специальные синтаксические конструкции, явно задающие область видимости каждого члена класса. Для этого используются модификаторы типа public (открытые члены класса), protected (доступные только из классов-потомков) и private (доступные только внутри класса). Для защиты внутреннего состояния объекта поля его класса не должны быть доступны извне. Поэтому поля объявляются скрытыми, а для доступа к их данным используются специальные методы доступа. Такие методы либо возвращают значение поля, либо производят запись нового значения в него. При записи метод контролирует допустимость значения и его корректность (внутреннюю согласованность). Методы доступа в общем называют аксессорами, а в частности – геттерами (методы чтения) и сеттерами (методы записи).
Свойства объекта. Это псевдополя, доступные для чтения и/или записи. Свойства внешне выглядят как поля и используются аналогично доступным полям, однако при обращении к ним происходит вызов методов доступа. Таким образом, свойства можно рассматривать как поля данных, сопровождающие доступ к внутренним данным объекта какими-либо дополнительными действиями например, когда изменение координаты объекта сопровождается его перерисовкой на новом месте. Свойства, по сути лишь скрывают вызов методов доступа. В C# объявление свойства содержит код методов доступа, который вызывается только при работе с этим свойством. В Delphi объявление свойства содержит только имена методов доступа, которые будут вызваны при обращении к полю.
Подходы к проектированию программ в целом
ООП ориентировано на разработку крупных программных комплексов, разрабатываемых командой программистов. Проектирование системы в целом, создание отдельных компонент и их объединение в конечный продукт выполняется разными людьми, и поэтому эффективное решение задачи требует подходов, уже изложенных ранее. Объектно-ориентированное проектирование состоит в описании структуры и поведения проектируемой системы, то есть, в ответе на два вопроса: 1) из каких частей состоит система, 2) в чём ответственность каждой части. Выделение частей производится по принципу, каждая часть должна иметь минимальный объём и точно определённый набор выполняемых функций, и при этом взаимодействовала с другими частями как можно меньше. Дальнейшее уточнение приводит к выделению более мелких фрагментов описания. По мере детализации описания и определения ответственности выявляются данные, которые необходимо хранить, а также близкие по поведению агенты, которые становятся кандидатами на реализацию в виде классов. После выделения компонентов и определения интерфейсов между ними реализация каждого компонента может проводиться практически независимо от остальных.
Определяющее значение имеет построение иерархии классов. Одна из главных проблем построения больших систем на основе ООП  определенность базового класса. Она состоит в том, что на поздних этапах разработки, когда иерархия классов выстроена и на её основе разработан код программы, сложно или даже невозможно внести какие-либо изменения в базовые классы иерархии при модификации пролграммы. Даже если эти изменения не затронут интерфейс базового класса, изменение его поведения может непредсказуемым образом отразиться на классах-потомках. В случае большой системы разработчик базового класса не в состоянии предугадать последствия изменений, их влияние на корректность работы классов-потомков.
Родственные методологии
Компонентно-ориентированное программирование (КОП)  следующий этап развития ООП. Это своеобразная надстройка над ООП, набор правил и ограничений, направленных на построение крупных развивающихся программных систем с большим временем жизни. Программная система в этой методологии представляет собой набор компонентов с хорошо определёнными интерфейсами. Изменения в существующую систему вносятся путём создания новых компонентов в дополнение или в качестве замены ранее существующих. При создании новых компонентов на основе ранее созданных запрещено использование наследования реализации  новый компонент может наследовать лишь интерфейсы базового. Таким образом, КОП обходит проблему определенности базового класса.
Прототипное программирование, сохранив часть черт ООП, отказалось от базовых понятий класса и наследования. Вместо механизма описания классов и порождения экземпляров предоставляется механизм создания объекта путём задания набора полей и методов, которыми объект должен обладать, и механизм клонирования объекта. Каждый вновь созданный объект является экземпляром, но без класса. Каждый объект может стать прототипом  быть использован для создания нового объекта с помощью операции клонирования. После клонирования новый объект можно изменять, в частности, дополнять новыми полями и методами. Клонированный объект либо становится полной копией прототипа, хранящей все значения его полей и дублирующей его методы, либо сохраняет ссылку на прототип, не включая в себя клонированных полей и методов до тех пор, пока они не будут изменены. В этом случае среда исполнения обеспечивает механизм делегирования. Если при обращении к объекту он сам не содержит нужного метода или поля данных, вызов передаётся прототипу, а от него, при необходимости, дальше по цепочке.

Производительность объектных программ
Буч указывает на следующие причины, приводящие к снижению производительности программ, разработанных на основе ООП.
1) Динамическое связывание методов. Обеспечение полиморфного поведения объектов приводит к необходимости связывать методы, вызываемые программой, не на этапе компиляции, а в процессе исполнения программы, на что тратится дополнительное время. При этом связывание требуется не более чем для 20% вызовов.
2) Глубина абстракции. ООП приводит к созданию многослойных приложений, где выполнение объектом требуемого действия сводится к множеству обращений к объектам более низкого уровня. В таком приложении методы часто вызываются, что снижает производительность.
3) Размытие кода. Код, используемый программой непосредственно и относящийся к оконечным классам иерархии наследования, находится не только в этих классах, но и в их классах-предках. Это приводит к снижению скорости трансляции программ (компоновщик подгружает описания всех классов иерархии) и их производительности в системах со страничной памятью (методы одного класса находятся на разных страницах памяти, активно обращающихся к унаследованным методам, в результате  частое переключение страниц).
3) Издержки инкапсуляции. Запрет на прямой доступ к полям класса извне приводит к необходимости использования методов доступа, что сопряжено с дополнительными расходами.
4) Динамическое создание и уничтожение объектов. Создаваемые объекты размещаются в “куче”, что менее эффективно, чем размещение их в стеке, а тем более, в статической памяти.
Несмотря на отмеченные недостатки, использование ООП в отдельных случаях дает более весомые результаты. Повышение производительности за счёт лучшей организации ООП-кода иногда компенсирует дополнительные расходы на организацию функционирования программы. В настоящее время ООП используется в большинстве промышленных проектов. Однако считать ООП наилучшей методикой программирования не следует. Сравнивая объектное и процедурное программирование, следует отметить. что процедурное лучше тогда, когда важны быстродействие и используемые ресурсы, но требуется больше времени для разработки, а объектное  когда важны управляемость проекта, его модифицируемость и скорость разработки.
4.5. События и событийная модель
События происходят в результате действий пользователя, например, щелчка кнопкой мыши или нажатия клавиши клавиатуры, в результате программного управления или действия другого объекта. Каждое событие возбуждает некоторое сообщение для другого объекта, например, операционной системе. Система обрабатывает это сообщение и передает его другим объектам. Каждый объект затем может предпринять соответствующие действия, основанные на его собственных инструкциях относительно этого конкретного сообщения, например, снова нарисовать себя на экране.
В традиционных "процедурной" программе (приложении) она сама отслеживает, какая часть его кода выполняется, и в какой последовательности. Ее выполнение начинается с первой строки кода и далее следует по предопределенному пути через всю программу, вызывая по мере необходимости соответствующие процедуры. В событийном приложении (управляемом событиями) выполнение кода не следует по заранее определенному пути: различные части кода выполняются в зависимости от произошедшего события. События инициируются действиями пользователя, сообщениями, поступающими от системы или других приложений, или даже от самого выполняемого приложения. Последовательность таких событий определяет последовательность выполнения кода в каждом новом сеансе работы приложения.
Так как нельзя заранее предугадать последовательность событий, код такого приложения должен иметь определенные предположения о состоянии среды во время своего выполнения, например, что в поле ввода должно быть некоторое значение до выполнения процедуры обработки этого значения. Поэтому приложение строится так, чтобы при любом возможном порядке следования событий обеспечивалось выполнение предположений. Например, может, блокироваться кнопка управления, которая запускает процедуру обработки, пока в поле ввода не появится нужное значение. Код приложения может сам инициировать события во время выполнения. Можно, например, программно изменить текст в текстовом поле (text box), путем инициирования события Change (Изменить) для этого поля. Если предполагалось, что это событие могло быть инициировано только взаимодействием с пользователем, можно получить неожиданный результат. Таких проблем не возникает при использовании традиционной процедурной модели. Именно по этой причине важно понимать событийную модель и помнить о ней при проектировании приложений.
Объекты, как уже отмечалось, обладают свойствами, методами и возможностью обмениваться сообщениями в результате возбуждения событий. Свойства – некоторые атрибуты объекта, методы - действия над объектом, события – реакции объекта в форме сообщений.
Объекты нашей повседневной жизни, например, воздушный шарик, имеют свойства, методы и события. Одни свойства шарика включают видимые атрибуты: размер, диаметр и цвет. Другие описывают его состояние (надут, не надут) или атрибуты, которые нельзя увидеть, например, возраст. По определению все шарики обладают этими свойствами, но значения этих свойств у разных шаров могут различаться. Шарик обладает присущими ему действиями (см. рисунок). Он обладает методами надувания (действие, связанное с надуванием шарика), сдувания (выпустить газ из шарика) и поднимания (если его отпустить, то он улетит). Эти действия способны выполнять все шарики.

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

Установка свойств шарика:

Обратим внимание на синтаксис кода. Объект Шар, за которым следует свойство, например Цвет, а далее знак присваивания значения (равенство), например Красный. Если применить оператор присваивания с другим значением (цветом), то можно изменить цвет шарика в самом коде. При разработке приложения свойствам можно присваивать значения в окне Properties.

Методы шарика вызываются следующим образом:

Синтаксис такой же, как для свойств. Объект (существительное), за которым следует точка и метод (глагол). В третьем примере (Шар.Подъем 5) присутствует дополнительный элемент, называемый параметром, который означает высоту подъема шарика. Некоторые методы для более детального описания выполняемого действия могут иметь и более одного параметра.
Каждому методу и событию соответствует определенная программа (процедура), реализующая соответствующие операции над объектом. Например, реакцию шарика на событие прокол (рис. справа). В данном случае код описывает поведение шарика при прокалывании. Вызывается метод Спустить, затем вызывается метод Звук с аргументом Бах! (звук "Б-а-а-х"). Так как шарик теперь не надут, то свойство Надуть принимает значение False (Ложь) и свойство Диаметр получает нулевое значение.

Тема 5
Алгоритмизация и разработка программного модуля
5.1. Определение алгоритма
Термин "алгоритм" применяется широко и не только в области вычислительной техники и программирования. Происходит от имени средневекового арабского математика Абу Джафара ибн Муссы аль-Хорезми. Редакция последней части имени в европейских языках привела к образованию термина "алгорифм" или "алгоритм". Первоначально термин "алгоритм" означал операции над числами. Потом это понимание утратилось, и его стали применять только к алгоритму Евклида.
Алгоритм Евклида был предназначен для нахождения наибольшего общего делителя пары натуральных чисел (m, n).
п1. {Нахождение остатка} r:=m mod n.
п2. {Замена} m:=n; n:=r.
п3. {Остановка?} Если n(0, то переход к п1.
п4. {Остановка процесса} m - искомое число.
Представленное описание алгоритма – это последовательность шагов, направленных на достижение некоторого результата (наибольшего общего делителя.).
Алгоритм – точное предписание, задающее алгоритмический процесс, который начинается с произвольного значения исходного данного из некоторой их совокупности. Процесс направлен на получение результата, полностью определенного этим данным.
Алгоритмический процесс – процесс последовательного преобразования конструктивных объектов (слов, чисел, пар слов, пар чисел, предложений и т.п.), происходящий дискретными шагами. Каждый шаг состоит в смене одного объекта другим.
Конструктивный объект - объект, над которым производится преобразование. К их числу относятся числа, буквы, слова, графы, логические выражения и т.д.
В алгоритме Евклида конструктивными объектами являются пары чисел. Смена конструктивных объектов, например, для чисел m=10, n =4 выглядит так: (10, 4) ( (4, 2) ( (2, 0).
Как правило, для заданного алгоритма можно выделить семь независимых параметров: 1) совокупность исходных данных, 2) совокупность промежуточных результатов, 3) совокупность результатов, 4) правило начала, 5) правило непосредственной переработки, 6) правило окончания, 7) правило извлечения результата. Для алгоритма Евклида эти параметры таковы.
I = {(m, n)| m ( n}.
P = {(m, n)| m ( n}.
R = {m|m > 0}.
Ввести пару чисел (m, n) таких, что m ( n.
(m, n) ( (n, m mod n).
Если в паре (m, n) n = 0, то останов.
Результатом является первое число пары (m, 0). Вывод m на устройство вывода.
Основные свойства алгоритма
Определенность - однозначность, исключающая произвольность толкования любого из предписаний и заданного порядка исполнения алгоритма.
Результативность - через определенное число шагов вычислительный процесс должен привести к выдаче результатов или сообщения о невозможности решения задачи.
Массовость - решение однотипных задач с различными исходными данными можно осуществлять по одному и тому же алгоритму, что обеспечивает создание типовых программ для решения задач при различных вариантах задания значений исходных данных.
Дискретность - вычислительный процесс, предопределенный алгоритмом, можно расчленить на отдельные этапы и элементарные операции.
Алгоритмизация - техника составления алгоритмов и программ для решения задач на ЭВМ.
5.2. Изобразительные средства описания алгоритмов
К ним относятся следующие способы: 1) словесный - запись на естественном языке, 2) структурно-стилизованный - запись на языке псевдокода, 3) программный - текст на языках программирования, 4) Графический - схемы графических символов.
1. Словесный способ записи алгоритмов это описание последовательных этапов обработки данных, реализуется в произвольном изложении на естественном языке с использованием общепринятых средств общения между людьми. Для исполнения такие описания неприемлемы, поскольку не формализованы, страдают многословностью и допускают неоднозначность толкования предписаний. Способ не имеет распространения.
Пример. Записать алгоритм Евклида на естественном языке.
Если числа равны, то взять любое из них в качестве ответа, в противном случае - продолжить выполнение алгоритма.
Определить число наибольшее из двух.
Заменить большее число разностью большего и меньшего чисел.
Повторить алгоритм с начала.
2. Структурно-стилизованный способ записи алгоритмов основан на формализованном представлении предписаний, задаваемых путем использования ограниченного набора типовых синтаксических конструкций. Такие средства описания алгоритмов называются псевдокодами. Разновидностью этого способа является алгоритмический язык в русской нотации (АЯРН).
Пример. Описать на АЯРН алгоритм решения задачи о принадлежности точки D треугольнику АВС.
алг Определение принадлежности точки треугольнику (действ Хa, Ya, Хb, Yb, Хс, Yс, Хd, Yd целое z лит а);
арг Хa, Ya, Хb, Yb, Хс, Yс. Хd, Yd;
рез z, a;
нач
действ S1, S2, S3, S4
вычислить значение S1, равное площади тр-ка АВС;
вычислить значение S2, равное площади тр-ка ABD;
вычислить значение S3, равное площади тр-ка ACD;
вычислить значение S4, равное площади тр-ка СDВ;
если S1 = S2+S3+S4
то z := 1, а := "точка внутри треугольника"
иначе z := 0, а := "точка вне треугольника"
все
напечатать значение а:
кон
3. Программный способ записи - это алгоритм, записанный на языке программирования, позволяющий на основе строго определенных правил формировать последовательность предписаний, однозначно отражающих смысл и содержание алгоритма с целью его последующего исполнения на ЭВМ.
Пример. Составить программу перевода температуры из градусов Цельсия в градусы Форенгейта на языке Бейсик.
PRINT "Перевод температуры из град. Цельсия в град. Форенгейта"
6 PRINT "Укажите температуру в град. Цельсия"
INPUT С
IF С = 99999 THEN 7
F=C*1.8+32
PRINT С, F
GOTO 6
7 END
3. Для графического изображения алгоритмов используются графические символы. Наиболее распространенными являются блочные символы (блоки), соединяемые линиями передач управления. Графическая запись алгоритма является наиболее наглядной (рис. справа). Схемы могут быть представлены также в виде структограмм или по имени их авторов, диаграммами Нэсси – Шнейдермана (рис. слева).
5.3. Блок-схемы алгоритмов. Графические символы
Блок-схема – это ориентированный граф, вершины которого могут быть одного из трех типов.
Функциональная вершина представляет функцию f: X(Y. Предикатная вершина представляет функцию-предикат p: X((T, F). Иначе логическое выражение, передающее управление по одной из двух ветвей. Объединяющая вершина представляет передачу управления от одной из двух входящих ветвей к одной выходящей ветви.
Функциональная вершина или вычислительный блок (рис. справа) представляет собой прямоугольник, в который вписываются расчетные формулы. Формула записывается таким образом, что вычисляемая переменная стоит слева, затем следует знак равенства (знак присваивания), далее - выражение.
Предикатная вершина изображается ромбом (рис. слева), внутри которого записывается проверяемое условие. В результате проверки выбирается один из двух путей вычислительного процесса. Если условие выполняется (ДА, +, 1), то следующим выполняется этап по стрелке ДА. Если условие не выполняется (НЕТ, -, 0), то - этап по стрелке НЕТ.
Объединяющая вершина изображается кружком или подразумевается в точке схода ветвей. Начало и окончание вычислительного процесса или алгоритма изображаются овалом (рис. справа), в котором записываются слова Начало, Останов или Конец.
При решении задач на ЭВМ исходные данные задаются разными способами, например, с клавиатуры, перфоленты, диска и т. д. Задание их численных значений называется вводом, а фиксация результатов расчета - выводом. Ввод исходных данных и вывод результатов, не привязанный к конкретному устройству, изображается параллелограммом. Внутри него пишется слово Ввод или Вывод, и перечисляются переменные (рис. справа). Для ввода/вывода на конкретные устройства используются специальные фигуры.
Линии потока показывают направление передачи управления между блоками. Направление линий потока сверху вниз и слева направо принимают за основное. Если линии потока основного направления не имеют изломов, то их направление стрелками можно не обозначать. В остальных случаях направление обозначают стрелкой.
5.4. Порядок разработки программного модуля
При разработке программного модуля используется следующий порядок: 1) изучение и проверка спецификации модуля, выбор языка программирования, 2) выбор алгоритма и структуры данных, 3) программирование (кодирование) модуля, 4) шлифовка текста модуля, 5) проверка модуля, 6) компиляция модуля.
Первый шаг разработки модуля представляет собой смежный контроль структуры программы снизу. Разработчик должен быть убежден, что она ему понятна и достаточна для разработки. В завершение выбирается язык программирования. В большинстве случаев он предопределен для всего программного средства, но в ряде случаев может выбираться и другой язык, более подходящий для реализации данного модуля, например, ассемблер.
На втором шаге устанавливается алгоритм решения поставленной задачи. Если таковой имеется, то выясняется целесообразность его применения. Структуры данных предопределяют логику реализации и качественные показатели модуля, поэтому их выбор - ответственное решение.
На третьем шаге создается текст модуля на языке программирования. Обилие деталей, которые следует учесть при реализации функций модуля, приводят к созданию трудно разбираемого и нечитабельного текста, содержащего ошибки и неточности. Поиск этих ошибок - трудоемкая задача. Поэтому важно пользоваться технологически обоснованной дисциплиной программирования. Впервые на это обратил внимание известный теоретик программирования Дейкстра. Он сформулировал основные принципы структурного программирования. Наиболее распространена дисциплина пошаговой детализации.
Следующий шаг (шлифовка) приводит текст модуля к завершенному виду в соответствии со спецификацией качества ПС. При программировании разработчик основное внимание уделяет реализации функций модуля, и оставляет недоработанными комментарии, допускает нарушения требований к стилю программы. При шлифовке он редактирует комментарии и включает в текст дополнительные для обеспечения примитивов качества. Редактирует текст программы для выполнения стилистических требований.
Шаг проверки – это ручную прогонку внутренней логики модуля до начала его отладки.
Последний шаг –завершение проверки модуля, его компиляция и переход к процессу отладки.
5.5. Структурное программирование
Программа должна быть понятной не только компьютеру, но и человеку - и разработчики, и тестовики, и сопроводители ПС будут неоднократно разбирать логику работы модуля. В современных языках программирования достаточно средств, чтобы запутать логику программы и сделать ее текст трудно понимаемым для человека и, как следствие, сделать модуль ненадежным или трудно сопровождаемым. Поэтому необходимы меры для выбора эффективных языковых средств и следование определенной дисциплине программирования. Дейкстра предложил строить программу как композицию из нескольких типов управляющих конструкций (структур), проявляющих логику ее работы. Программирование с использованием таких конструкций назвали структурным.
Основными конструкциями структурного программирования являются: следование, разветвление и повторение (рис. 10).
Компонентами этих конструкций являются обобщенные операторы (узлы обработки) S, S1, S2 и условие (предикат) P. В качестве обобщенного оператора выступает либо простой оператор языка программирования (операторы присваивания, ввода, вывода, обращения к процедуре), либо фрагмент программы, также являющийся композицией основных конструкций структурного программирования. Каждая из этих конструкций имеет по управлению только один вход и один выход. Тем самым, и обобщенный оператор имеет только один вход и один выход. Эти конструкции являются математическими объектами. Доказано, что для каждой неструктурированной программы можно построить функционально эквивалентную (т.е. решающую ту же задачу) структурированную программу. Для структурированных программ можно математически доказывать некоторые свойства, позволяющие обнаружить в ней отдельные ошибки.
Структурное программирование иногда называют "программированием без GO TO". Однако дело здесь не в операторе GO TO, а в его беспорядочном использовании. Часто оператор перехода (GO TO) используется для реализации структурных конструкций, что не нарушает принципов структурного программирования. Запутывают программу "неструктурные" операторы перехода, особенно переход к оператору, расположенному в тексте модуля выше (раньше) выполняемого оператора перехода. Однако попытка избежать оператора перехода в некоторых простых случаях приводит к громоздким структурированным программам, что не улучшает их ясность и обуславливает появление дополнительных ошибок. Рекомендуется избегать употребления оператора перехода всюду, где это возможно, но не ценой ясности программы.
К полезным случаям использования оператора перехода относится выход из цикла или процедуры по особому условию, "досрочно" прекращающего их работу и тем самым локально нарушающего структурированность программы. Усложняет структуру реализация реакции на возникающие исключительные ситуации, так как при этом необходимо не только осуществить досрочный выход из структуры, но и произвести обработку этой ситуации, например, выдать диагностическую информацию. Обработчик исключительной ситуации может находиться на любом уровне структуры программы, а обращение к нему производиться с разных нижних уровней. Приемлемой является "неструктурная" реализация реакции на исключительные ситуации, когда обработчики этих ситуаций помещаются в конце той структуры, ситуации которой они и будет обрабатывать. Обработчик программируется таким образом, что после окончания своей работы производит выход из своей структуры, в конце которой помещен. Обращение к обработчику производится оператором перехода из данной структуры, включая любую вложенную в нее структурную единицу.
5.6. Пошаговая детализация и понятие о псевдокоде
Структурное программирование отвечает на вопрос, каким должен быть текст модуля. Но возникает другой вопрос, как должен действовать программист, чтобы построить такой текст. Часто программирование модуля начинают с построения его блок-схемы, описывающей в общих чертах логику его работы. Однако современная технология программирования не рекомендует этого делать без компьютерной поддержки. Хотя блок-схемы позволяют наглядно представить логику работы модуля, при его ручном кодировании на языке программирования возникает специфический источник ошибок - отображение двумерных структур, каковыми являются блок-схемы, на линейный текст, представляющий модуль, содержит опасность искажения логики работы модуля. Исключением является случай, когда блок-схемы формализованы до уровня графической редакции и автоматической генерации текста на языке программирования, как, например, в Р-технологии.
Для построения текста модуля используется пошаговая детализация. Сущность этого метода заключается в разбиении процесса разработки текста модуля на ряд шагов. На первом шаге описывается общая схема работы модуля в обозримой линейной текстовой форме с использованием очень крупных понятий. Это описание не является полностью формализованным и ориентировано на восприятие человеком. На каждом следующем шаге производится детализация или уточнение понятий, введенных на предыдущем шаге. В результате последовательности таких шагов создается описание уточняемых понятий или в терминах базового языка программирования, или в той же форме, что и на первом шаге с использованием новых уточняемых понятий. Этот процесс завершается, когда все понятия будут окончательно уточнены, т.е. выражены на языке программирования. Последним шагом является получение текста модуля на языке программирования путем замены всех вхождений уточняемых понятий их описаниями и выражение всех вхождений конструкций структурного программирования средствами языка программирования.
Пошаговая детализация связана с использованием частично формализованного языка для представления указанных описаний, который получил название псевдокода. Этот язык позволяет использовать формализованные конструкции структурного программирования вместе с неформальными фрагментами на естественном языке для представления обобщенных операторов и условий. В качестве обобщенных операторов и условий могут выступать и соответствующие фрагменты на базовом языке программирования.
Головным описанием на псевдокоде является внешнее оформление модуля на базовом языке программирования, которое содержит: 1) начало модуля на базовом языке, т.е. первое предложение или заголовок этого модуля; 2) раздел описаний на базовом языке, причем вместо описаний процедур и функций ( только их внешнее оформление; 3) неформальное обозначение последовательности операторов тела модуля как одного обобщенного оператора, а также неформальное обозначение тела каждого описания процедуры или функции как одного обобщенного оператора; 4) последнее предложение (конец) модуля на базовом языке. Внешнее оформление описания процедуры или функции представляется аналогично. По Дейкстра раздел описаний лучше представить неформальным обозначением, произведя его детализацию в виде отдельного описания.
Неформальное обозначение обобщенного оператора на псевдокоде производится на естественном языке произвольным предложением, раскрывающим в общих чертах его содержание. Единственно формальным требованием к оформлению обозначения является - предложение должно занимать целиком одно или несколько графических (печатных) строк и завершаться точкой или другим знаком, выделенным для этого.
Для каждого неформального обобщенного оператора создается отдельное описание, выражающее логику его работы с помощью композиции основных конструкций структурного программирования и других обобщенных операторов. В качестве заголовка выступает неформальное обозначение детализируемого обобщенного оператора. Основные конструкции структурного программирования представляются в виде (рис. 11). Здесь условие либо явно задается на базовом языке программирования в качестве булевского выражения, либо неформально представляется на естественном языке некоторым фрагментом, раскрывающим смысл этого условия. В последнем случае создается отдельное описание, детализирующее это условие, с указанием в качестве заголовка обозначения условия на естественном языке. В качестве обобщенного оператора на псевдокоде можно использовать частные случаи оператора перехода (рис. 12)
Последовательность обработчиков исключительных ситуаций задается в конце модуля или описания процедуры (функции) в виде обработчика представленного справа. Отличие обработчика исключительной ситуации от процедуры без параметров заключается в том, что после выполнения процедуры управление возвращается к оператору, следующему за обращением к ней, а после выполнения исключения управление возвращается к оператору, следующему за обращением к модулю или процедуре (функции), в конце которого (которой) помещено исключение.
Рекомендуется на каждом шаге детализации создавать содержательное, но легко обозримое описание, так чтобы оно размещалось на одной странице текста. Такое описание является композицией пяти-шести конструкций структурного программирования. Рекомендуются вложенные конструкции смещать на несколько позиций вправо (рис. 13). В результате будет получено описание логики работы по наглядности конкурентное с блок-схемами, но обладающее существенным преимуществом ( сохраняется его линейность.
Наряду с пошаговой детализацией Дейкстра предложил еще две принципиальные и перспективные идеи. Во-первых, вместе с уточнением операторов пошагово уточнять используемые структуры данных. Во-вторых, создавать на каждом шаге некоторую виртуальную машину и в ее терминах производить детализацию всех уточняемых понятий. Таким образом, Дейкстра, по существу, предложил горизонтально-слоевую деталировку, что является развитием его идеи о слоистых системах на уровне разработки модулей. Метод разработки модуля, предложенный Дейкстра, поддерживается пакетами языка АДА и средствами объектно-ориентированного программирования.

Тема 6
ТЕСТИРОВАНИЕ И ОТЛАДКА ПРОГРАММНОГО СРЕДСТВА
6.1. Основные понятия
Отладка ПС ( это деятельность, направленная на обнаружение и исправление ошибок с использованием процессов выполнения программ. Тестирование ПС ( это процесс выполнения программ на некотором наборе данных, для которого заранее известен результат применения или известны правила поведения программ. Указанный набор данных называется тестовым или просто тестом. Отладку можно представить в виде многократного повторения процессов тестирования, в результате которых констатируется наличие ошибки, устанавливаются их места в программах и документации и редактируются программы и документация с целью устранения обнаруженных ошибок
Отладка = Тестирование + Поиск ошибок + Редактирование.
В зарубежной литературе под отладкой в основном понимают процесс поиска и исправления ошибок, хотя их наличие устанавливается только в результате тестирования. Иногда тестирование и отладку считают синонимами. В нашей стране в понятие отладки включается и тестирование. Причем тестирование используется как часть процесса аттестации ПС.
6.2. Принципы и виды отладки ПС
Успех отладки предопределяет рациональная организация тестирования. При отладке ПС отыскиваются и устраняются те ошибки, наличие которых установлено посредством тестирования. Тестирование не доказывает правильность средства, оно демонстрирует наличие в нем ошибки. Нельзя гарантировать, что в результате тестирования ПС на ограниченном наборе тестов, будут установлены все ошибки. В связи с этим возникают две задачи. Первая – подготовить такой набор тестов, чтобы обнаружить по возможности большее число ошибок. Однако чем дольше продолжается процесс тестирования (и отладки в целом), тем больше стоимость ПС. Отсюда вторая задача: определить момент окончания отладки ПС или отдельной его компоненты. Признаком окончания отладки является полнота охвата тестами ситуаций, возникающих при выполнении программ, и относительно редкое проявление ошибок на конечном отрезке тестирования. Последнее определяется согласно требуемой степени надежности ПС.
Для подготовки оптимального набора тестов необходимо заранее его планировать и использовать рациональную стратегию его проектирования. Проектирование тестов начинается сразу после завершения этапа внешнего описания ПС. Возможны разные подходы к выработке стратегий проектирования, которые размещаются между двумя крайними подходами (рис. 14). Левый крайний подход заключается в том, что тесты проектируются только на основе изучения спецификаций средства (внешнего описания, описания архитектуры и спецификаций модулей). Строение модулей не учитывается, они рассматриваются как черные ящики. Такой подход требует полного перебора всех наборов входных данных, так как в противном случае некоторые участки программ могут оказаться не задействованными при пропуске неполного набора тестов, вследствие чего содержащиеся в них ошибки не будут обнаружены. Однако тестирование программного средства полным множеством наборов входных данных практически неосуществимо. Правый крайний подход заключается в том, что тесты проектируются на основе изучения текстов программ с целью тестирования путей их выполнения. Если принять во внимание наличие в программах циклов с переменным числом повторений, то различных путей выполнения программ может оказаться чрезвычайно много, так что их полное тестирование также будет практически неосуществимо.
Рациональная стратегия проектирования тестов располагается между этими крайними подходами, но ближе к ее левому краю. Она включает проектирование значительной части тестов по спецификациям, а остальной - по текстам программ. При этом стратегия проектирования по спецификациям базируется на принципах: 1) на каждую используемую функцию или возможность ( хотя бы один тест, 2) на каждую область и на каждую границу изменения какой-либо входной величины ( хотя бы один тест, 3) на каждую особую ситуацию, указанную в спецификациях, ( хотя бы один тест.
В то время как стратегия проектирования по текстам программ базируется на принципе: каждая команда каждой программы должна проработать хотя бы на одном тесте.
Рациональную стратегию проектирования тестов можно конкретизировать на основании следующего принципа: для каждого программного документа, включая тексты программ, должны проектироваться свои тесты с целью выявления в нем ошибок.
Различают два основных вида отладки ПС: автономную и комплексную. Автономная отладка означает последовательное раздельное тестирование различных частей программ, с поиском и исправлением фиксируемых ошибок. Фактически отладка включает раздельную отладку программных модулей и их сопряжений. Комплексная отладка означает тестирование ПС в целом с поиском и исправлением фиксируемых при тестировании ошибок во всех документах, включая тексты программ. К таким документам относятся: определение требований к ПС, его спецификация качества, функциональная спецификация, описание архитектуры и тексты программ.
6.3. Заповеди отладки ПС
По мере роста числа обнаруженных и исправленных ошибок растет относительная вероятность существования в ПС необнаруженных ошибок. Это объясняется тем, что при росте числа ошибок, обнаруживаемых на каждом последующем этапе разработки, уточняется наше представление об общем числе допущенных ошибок, а значит, уточняется и представление о числе еще необнаруженных ошибок.
Рассмотрим шесть заповедей по организации отладки.
1. Считай тестирование ключевой задачей разработки ПС, поручай его самым квалифицированным и одаренным программистам. Нежелательно тестировать собственную программу.
2. Хорош тот тест, для которого высока вероятность обнаружения ошибки, а не тот, который демонстрирует "правильную" работу программы.
3. Готовь тесты, как для "правильных", так и для "неправильных" данных.
4. Документируй пропуск тестов через компьютер. Детально изучай результаты каждого теста. Избегай тестов, пропуск которых нельзя повторить.
5. Каждый модуль подключай к программе только один раз. Никогда не изменяй программу, чтобы облегчить ее тестирование.
6. Пропускай заново все тесты, связанные с проверкой работы отдельной программы или ее взаимодействия с другими программами, если в нее были внесены изменения.
6.4. Автономная отладка ПС
При автономной отладке каждый модуль тестируется в некотором программном окружении, кроме случая одномодульной программы. Это окружение включает уже отлаженные модули и модули, управляющие отладкой - отладочные модули. Таким образом, при автономной отладке всегда тестируется некоторая программа, созданная для тестирования отлаживаемого модуля. Такая программа, называемая тестируемой, лишь частично совпадает с отлаживаемой программой, кроме случая отладки последнего модуля. В процессе отладки производится наращивание тестируемой программы отлаженными модулями - при переходе к отладке следующего модуля в его программное окружение добавляется последний отлаженный модуль. Процесс наращивания программного окружения отлаженными модулями называется интеграцией программы. Отладочные модули зависят от порядка отладки модулей программы, находящегося в отладке модуля и используемого теста.
При восходящем тестировании окружение модуля содержит только один отладочный модуль, кроме случая отладки последнего модуля программы, который является головным в тестируемой программе. Такой отладочный модуль называется ведущим или драйвером. Ведущий модуль подготавливает информационную среду для тестирования отлаживаемого модуля, т. е. формирует ее состояние, в частности, путем ввода некоторых тестовых данных, осуществляет обращение к отлаживаемому модулю и после окончания его работы выдает необходимые сообщения. При отладке модуля для разных тестов могут составляться и разные ведущие модули.
При нисходящем тестировании окружение отлаживаемого модуля включает отладочные имитаторы-заглушки не отлаженных модулей, которые и выступают в качестве отладочных модулей. К таким модулям относятся те модули, к которым может обращаться отлаживаемый модуль, а также еще не отлаженные модули, к которым могут обращаться уже отлаженные модули, включенные в окружение. Некоторые из имитаторов при отладке отдельного модуля могут изменяться в зависимости от тестов.
На практике в окружении отлаживаемого модуля могут содержаться отладочные модули обоих типов, если используется смешанная стратегия тестирования. Это связано с тем, что восходящее и нисходящее тестирование имеют свои достоинства и недостатки.
Достоинства восходящего тестирования: простота подготовки тестов и возможность полной реализации плана тестирования модуля. Это связано с тем, что тестовое состояние информационной среды готовится ведущим отладочным модулем непосредственно перед обращением к отлаживаемому модулю.
Недостатки восходящего тестирования:
тестовые данные, как правило, готовятся не в той форме, которая рассчитана на пользователя, кроме случая отладки последнего головного модуля программы;
большой объем отладочного программирования - для отладки каждого модуля подготавливается несколько ведущих отладочных модулей, формирующих состояние информационной среды для разных тестов;
необходимость специального тестирования сопряжений модулей.
Достоинствам нисходящего тестирования:
большинство тестов готовится в форме, рассчитанной на пользователя;
во многих случаях относительно невелик объем отладочного программирования - имитаторы модулей, как правило, просты и каждый пригоден для большого числа тестов;
нет необходимости в тестировании сопряжений модулей.
Недостаток нисходящего тестирования: состояние информационной среды перед обращением к отлаживаемому модулю ( результат применения уже отлаженных модулей к тестовым данным или данным, выданными имитаторами. Это, во-первых, затрудняет подготовку тестов для вновь отлаживаемого модуля и требует высокой квалификации тестовика, а, во-вторых, осложняет реализацию полного плана тестирования модуля. Указанный недостаток вынуждает разработчиков иногда применять восходящее тестирование даже в случае нисходящей разработки. Однако чаще применяют некоторые модификации нисходящего тестирования, либо некоторую комбинацию нисходящего и восходящего тестирования. Исходя из того, что нисходящее тестирование является предпочтительным, рассмотрим некоторые приемы, позволяющие преодолеть указанные недостатки.
Прежде всего, необходимо организовать отладку программы так, чтобы первыми были отлажены модули, реализующие ввод данных, ( тогда тестовые данные можно готовить в форме, рассчитанной на пользователя. Не всегда этот ввод осуществляется в головном модуле, поэтому, в первую очередь отлаживаются цепочки модулей, ведущие к модулям, осуществляющим указанный ввод. Пока модули, осуществляющие ввод данных, не отлажены, тестовые данные поставляются имитаторами, которые либо вводят эти данные извне либо уже содержат их в себе как часть.
При нисходящем тестировании отдельных модулей некоторые состояния информационной среды вообще не возникают ни при каких входных данных. Казалось бы, что в этих случаях можно не тестировать отлаживаемый модуль, так как даже наличие ошибок никак не скажется на выполнении программы. Однако это неверный подход. При внесении изменений в программы, например, при сопровождении ПС, ранее не использованные для тестирования модуля состояния информационной среды могут возникнуть, что потребует дополнительного тестирования модуля, хотя сам модуль не изменился, а этого при рациональной организации отладки можно было бы избежать. Для тестирования отлаживаемого модуля в указанных ситуациях иногда используют имитаторы для создания соответствующего состояния информационной среды. Чаще пользуются модифицированным вариантом нисходящего тестирования, при котором отлаживаемые модули перед их интеграцией тестируются отдельно. В этом случае в окружении отлаживаемого модуля появляется ведущий модуль, наряду с имитаторами модулей, к которым может обращаться отлаживаемый модуль. Более целесообразна другая модификация нисходящего тестирования. После завершения тестирования модуля на достигаемых состояниях информационной среды следует провести отдельное тестирование на остальных состояниях информационной среды.
Часто применяется комбинация восходящего и нисходящего тестирования, названная методом сандвича. Его суть заключается в одновременном осуществлении как восходящего, так и нисходящего тестирования, пока эти два процесса не столкнутся на каком-либо срединном модуле программы. Этот метод позволяет воспользоваться достоинствами и восходящего, и нисходящего тестирования, а также нейтрализовать их недостатки.
Важным моментом при автономной отладке является тестирование сопряжения модулей. Спецификации модулей, кроме головного, используются в программе в двух ситуациях. Во-первых, при разработке текста модуля. Во-вторых, при написании обращения к модулю из других модулей программы. И в том, и в другом случае в результате ошибки может быть нарушено требуемое соответствие заданной спецификации модуля. Во избежание этого и предназначено тестирование сопряжения модулей. При нисходящем тестировании сопряжения тестируются попутно каждым пропускаемым тестом, что является достоинством нисходящего тестирования. При восходящем тестировании обращение к отлаживаемому модулю производится не из модулей отлаживаемой программы, а из ведущего отладочного модуля. Поэтому, приступая, в процессе интеграции программы, к отладке нового модуля, приходится тестировать каждое обращение к ранее отлаженному модулю с целью обнаружения несогласованности этого обращения с телом соответствующего модуля. Не исключено, что виновником несогласованности окажется ранее отлаженный модуль. Таким образом, приходится в новых условиях частично повторять тестирование ранее отлаженного модуля, при этом возникают те же трудности, что и при нисходящем тестировании.
Автономное тестирование модуля целесообразно проводить в пошаговом порядке.
Шаг 1. На основании спецификации отлаживаемого модуля готовятся тесты для всех мыслимых ситуаций, границ областей допустимых и недопустимых значений входных данных, областей их изменения, и всех недопустимых условий.
Шаг 2. Проверяется текст модуля и устанавливается, что каждое направление разветвлений будет пройдено хотя бы на одном тесте. Добавляются недостающие тесты.
Шаг 3. Проверяется текст модуля и устанавливается, что тесты обеспечивают полноту отладки каждого цикла: тело цикла не выполняется ни разу, выполняется один раз и выполняется максимальное число раз. Добавляются недостающие тесты.
Шаг 4. Проверяется текст модуля и устанавливается, что имеются тесты, проверяющие чувствительность модуля к особым значениям входных данных. Добавляются недостающие тесты.

Тема 7
Методы разработки алгоритмов
Среди многообразия методов разработки алгоритмов выделяется небольшой набор основных, применяемых наиболее часто и лежащих в основе многих процедур и алгоритмов.
7.1. Метод частных целей
Этот метод имеет общую формулировку "Необходимо свести трудную задачу к последовательности более простых задач". С одной стороны, это естественно и разумно, а, с другой стороны, в конкретной задаче часто трудно указать способ ее разбиения на набор более простых задач. Все зависит от опыта и искусства программиста. Несмотря на общность метода и отсутствие рецептов его применения, важно освоить этот метод, поскольку он лежит в основе решения многих задач и по сути является основой алгоритмизации и программирования. Разработка любого алгоритма должна начинаться с ответа на вопрос "Можно ли задачу разбить на последовательность более простых задач?". Рассмотрим метод на задаче сетевого планирования.
Задача. Имеется комплекс взаимосвязанных работ. Для каждой из N работ задана ее трудоемкость в человеко-часах. Необходимо расставить K имеющихся работников так, чтобы длительность выполнения всего комплекса работ была минимальной. При этом запрещено перемещать работников с одной работы на другую в ходе выполнения работ.
Взаимосвязь работ задается сетевым графиком, представляющим собой ориентированный граф без петель и контуров и состоящий из конечного множества вершин и попарно соединяющих их дуг (i, j). Вершины графа – события, а дуги – работы. Работа – трудовой процесс, требующий затрат времени и ресурсов, характеризуется трудоемкостью. Событие – факт окончания всех предшествующих ему работ и возможность начать следующие за ним работы. Работа сетевого графика определяется i-ым событием, предшествующим началу работы, и j-ым событием, указывающим на окончание работы. Работа обозначается (i, j), продолжительность ее выполнения - tij, а трудоемкость - rij. К числу особых событий относятся исходное 0-ое событие, соответствующее началу выполнения работ, и M-ое завершающее событие, отражающее завершение всех работ. Остальные события нумеруются исходя из требования, чтобы не существовало некоторой работы (i, j), для которой i > j. Путь сетевого графика – любая непрерывная последовательность событий и работ по направлению стрелок. Множество путей, соединяющих два события i и k, обозначим, как L(i, k). Наибольший интерес представляют полные пути, т.е. пути из 0 в M – (0, M). Полный путь с наибольшей продолжительностью Iкр называется критическим.
Iкр = I ( (0, M), max T(I),
где T(I) –продолжительность I -го пути. Рассмотрим конкретный комплекс работ, заданных сетевым графиком, в котором N = 7, K = 10, а множество работ задано графом (рис. справа) A = {(0, 1), (0, 2), (1, 3), (1, 4), (2, 4), (3, 5), (4, 5)}. Числа над дугами графа - трудоемкости работ. Множество полных путей - L(0, 5) = {I1, I2, I3}, где I1 = {(0, 1), (1, 3), (3, 5)}, I2 = {(0, 1), (1, 4), (4, 5)}, I3 = {(0,2), (2,4), (4,5)}.
Для K = 7 задача имеет тривиальное решение, так как на каждую работу приходится по одному работнику. При K = 8 появилась бы возможность поставить "лишнего" работника на одну из работ комплекса. Тогда вариантов такой расстановки было бы 7 по количеству работ. При K = 9 вариантов расстановки было бы уже 72, а в нашем случае – 73. Количество вариантов с ростом размерности задачи быстро растет и решение ее путем полного перебора неэффективно.
Один из простых путей решения задачи состоит в том, чтобы разбить задачу на три шага. На первом шаге решить задачу, куда поставить 8-го работника. Зафиксировав рабочего, на втором шаге решать задачу, куда поставить 9-го работника и т.д. Таким образом, сложная задача свелась к трем последовательным более простым задачам. В общем случае число таких простых задач равно (K - N). Каждая из этих однотипных задач формулируется так.
Необходимо принять решение о добавлении одного работника на одну из работ комплекса так, чтобы время выполнения всего комплекса по полученной расстановке было минимальным.
При конкретной расстановке работников по каждой работе время выполнения отдельной (i, j)-ой работы составит tij = rij / kij, где kij - количество работников на (i, j)-ой работе. В нашей задаче при исходной расстановке семи работников по одному на каждую работу времена их выполнения численно равны трудоемкостям, а длительности полных путей составят
T(I1) = t01 + t13 + t35 = 1 + 2 + 4 = 7,
T(I2) = t01 + t14 + t45 = 1 + 2 + 1 = 4,
T(I3) = t02 + t24 + t45 = 2 + 3 + 1 = 6.
Продолжительность выполнения комплекса работ определяется продолжительностью самого длинного из полных путей (критического пути) I1 и равна 7 часам. Очевидно, чтобы уменьшить эту длительность, следует поместить "лишнего" 8-го работника на одну из работ критического пути. Ставя работника на каждую работу этого пути (0,1), (1,3), (3,5) и сравнивая получающиеся варианты, выбираем из них вариант с наименьшей продолжительностью выполнения комплекса работ. В нашем случае это вариант с размещением работника на работу (3,5). Таким образом, задача размещения одного работника решена и переходим к следующей задаче последовательности. В общем случае, при поиске решения по данному алгоритму придется проанализировать не более (K-N)(N вариантов.
7.2. Метод подъема
Метод относится к общему рецепту разработки алгоритмов. Его суть заключается в том, что процесс решения начинается с принятия начального предположения или построения начального решения задачи. Затем начинается движение вверх от начального уровня по направлению к уровням с лучшим решением. Когда достигается уровень, из которого дальнейшее продвижение вверх невозможно, процесс прекращается. Рассмотрим работу метода, на предыдущей задаче.
В задаче расстановки рабочих начальным решением будет какая-либо их расстановка по работам. Из множества вариантов начальной расстановки возьмем простейший вариант с равномерным распределением работников по работам kij = [K/N] для любых i и j, [] - целая часть числа. Далее оставшееся число работников K mod N распределяется по правилу один работник на работу с наибольшей трудоемкостью и, если их резерв не исчерпан, ищется следующая по трудоемкости работа, на которую ставится очередной работник. Процесс заканчивается, когда резерв работников исчерпан. В нашем примере после завершения процесса начальной расстановки сложится такая ситуация: k01=1, k02=2, k13=1, k24=2, k34=2, k14=1, k45=1, а длительности полных путей составят
T(I1) = t01 + t13 + t35 = 1/1 + 2/1 + 4/2 = 5,
T(I2) = t01 + t14 + t45 = 1/1 + 2/1 + 1/1 = 4,
T(I3) = t02 + t24 + t45 = 2/2 + 3/2 + 1/1 = 3,5.
Путь I1 является критическим путем. Далее организуется процесс восхождения от худшего к лучшему варианту. Для этого следует переместить одного работника с работы некритического пути на одну из работ критического пути. Если длительность критического пути уменьшилась, то процесс повторяется - работник перемещается на следующую работу этого пути, если – нет, то перемещается работник с другой работы некритического пути и т.д. Если ни одно из перемещений не приводит к улучшению результата, то алгоритм подъема завершает свою работу. Выбор работы критического пути, на которую перемещается работник с некритического пути, производится по критерию
13 EMBED Equation.3 1415.
Для Iкр= I1= {(0, 1), (1, 3), (3, 5)}, максимум достигается для работы (1, 3). Согласно начальному распределению, кандидатами на перемещение работника могут быть только работы (0,2) и (2,4), поскольку на других работах некритических путей имеется только по одному работнику и резерв для перемещения отсутствует. Произведя подъем, получим следующее распределение работников: k01=k02=k14=k45=1, k13=k24= k34=2, а длительности составят: T(I1)=4, T(I2)=4, T(I3)=4,5. Полученный результат является уровнем останова подъема, так как никакое другое перемещение не улучшает этот результат. Не во всех случаях метод подъема достигает оптимального результата.
7.3. Программирование с отходом назад
В основе алгоритмов искусственного интеллекта лежит перебор вариантов. Программирование перебора вариантов – сложная задача, так как алгоритмы перебора ищут решение не по заданным правилам, а путем проб и ошибок. Схемы перебора не укладываются в схемы циклов языков программирования. При этом прямой перебор всех возможных вариантов, как правило, неосуществим из-за их огромного количества. Метод программирования с отходом назад позволяет организовать исчерпывающий поиск решения задачи, не прибегая к перебору всех возможных вариантов. Рассмотрим пример, демонстрирующий основные свойства алгоритмов с отходом назад, и на его основе составим общую блок-схему алгоритмов перебора вариантов.
Задача о восьми ферзях. Найти все способы расстановки на шахматной доске восьми ферзей так, чтобы они не угрожали друг другу, т.е. чтобы на доске 8(8 никакие два ферзя не стояли на одной вертикали, горизонтали или диагонали. Очевидно, больше 8 ферзей на доске не расставить, так как все они должны стоять на разных горизонталях и вертикалях, а их всего по 8. Покажем, что 8 ферзей расставить можно, например, так как показано на рисунке справа. Однако значительно труднее определить общее число таких расстановок, в чем и состоит задача.
Множество всех расстановок ферзей, среди которых требуется найти нужное подмножество, представим с помощью ориентированного дерева. На нем организуем поиск нужного варианта. Ориентированное дерево – это связный граф без циклов с выделенной вершиной (корнем), в котором между корнем и любой вершиной существует единственный путь. У дерева 9 уровней, номер уровня i определяет номер вертикали, на которую устанавливается i-ый ферзь. Восемь ветвей, выходящих из каждой вершины i–го уровня, соответствует восьми горизонтальным позициям ферзя, устанавливаемого на (i+1)–ой вертикали (см. рис.).
По условию задачи ферзи не должны бить друг друга, поэтому из рассмотрения исключаются вершины дерева, соответствующие уже занятым горизонталям и диагоналям. Тогда алгоритм перебора вариантов сводится к прохождению всех связных вершин дерева, начиная, например, с левой ветви, двигаясь вниз по нему до тех пор, пока не достигнута вершина последнего уровня. Если попытка установить (i+1)-го ферзя неудачна, то отходим назад на один уровень и проверяем, можем ли спуститься вниз по другой ветви. Если спуск возможен, то проводим его опять по самой левой из не пройденных ветвей (отход в бок), иначе отходим назад еще на один уровень и пытаемся спуститься по следующей из не пройденных ветвей и т.д., пока не переберем все 8 горизонтальных полей для (i+1)–й вертикали. Если вершина последнего уровня достигнута, то найден очередной вариант расстановки ферзей. Возвращаемся к корню и начинаем движение вниз по следующей из не пройденных ветвей и т.д. до тех пор, пока не останется не пройденных ветвей.
При такой организации перебора возможно не более 88=224 вариантов, что примерно равно 106. На самом деле их будет гораздо меньше в силу условия, что ферзи не бьют друг друга.
Введем два понятия – номер хода i, соответствующий порядковому номеру ферзя или уровню графа, и номер варианта j – порядковый номер попытки установить этого ферзя после того, как положение предыдущих ферзей зафиксировано. Размещая одного ферзя за другим, в лучшем случае будут расставлены все восемь ферзей, в худшем – столкнемся с ситуацией, когда все варианты расстановки i–го ферзя на i–ой вертикали исчерпаны, т.е. не найден вариант, в котором его не били бы другие (i-1) уже расставленных ферзей. Тогда и приходится вернуться назад на (i-1)-ый уровень и перейти к следующему варианту расстановки предыдущего (i-1)-го ферзя. Для этого надо иметь последний рассмотренный вариант установки (i-1)-го ферзя, помнить его. Далее, увеличив номер варианта, продолжать просмотр вариантов установки (i-1)-го ферзя. Таким образом, увеличивая номер хода, движемся вперед, а для каждого очередного хода движемся вбок, подбирая допустимый вариант, переходя к следующему ходу, если таковой найден. Если вариант не найден, то возврат назад на ход и продолжение движения вбок, начиная с последнего варианта, рассмотренного на этом ходе. Установив последнего ферзя, фиксируем результат решения и возвращаемся назад на поиск нового решения, пока не будут исчерпаны все допустимые расстановки. Ниже представлена блок-схема перебора.
Детализируем блок-схему задачи. Для этого возьмем доску размером n(n и положим n=8. Будем ставить i-го ферзя на i–ую вертикаль. Для записи положения i–го ферзя заведем массив позиция[n] размерности n. Тогда в блоке прописка вариантов будет заноситься такое j, что i-ый ферзь, стоящий на пересечении i–й вертикали и j–ой горизонтали, не бьется ранее установленными (i-1) ферзями. Блок запись решения и его номера реализует печать номера расстановки и массива позиция[n], содержащего искомую расстановку. При движении назад надо установить номер последнего варианта предыдущего хода. Эта задача решается автоматически, так как последний вариант из позиция[n] будет занесен в j.
Для установки первого ферзя потребуется записать вертикаль и горизонталь, предшествующие 1-ой вертикали и горизонтали. Используем для этого фиктивную вертикаль i=0 и горизонталь j=0. При установке i–го ферзя необходима проверка, бьется ли поле i–го ферзя предыдущими, уже установленными ферзями. Для этого требуется проверить, стоят ли ферзи на одной горизонтали, на одной восходящей диагонали (слева снизу - направо вверх) и на одной заходящей диагонали (слева сверху – направо вниз). Для организации проверки вводим три логических массива: горизонт[n] – список горизонталей, восход[2n] – список восходящих диагоналей, заход[2n] – список заходящих диагоналей. Тогда полю (i,j), где 0 ( i ( n, 0 ( j ( n, соответствует вертикаль i, горизонталь j, восходящая диагональ n+j-i (n+j-i=const - уравнения линий с углом наклона 45(), заходящая диагональ i+j (i+j=const – уравнения линий с углом наклона -45() (см. рис.). В блоке прописка варианта надо заносить в массивы горизонт, восход, заход отметку о том, что заняты горизонталь и две соответствующие диагонали того поля, куда установлен новый ферзь (горизонт[j]=true, восход[n+j-i]=true, заход[i+j]=true). В блоке выписка последнего варианта, наоборот – убрать отметки о занятости этого поля (горизонт[j]=false, восход[n+j-i]=false, заход[i+j]=false). Это легко осуществить, так как на одной горизонтали и диагонали может находиться только один ферзь.
Наиболее сложным разделом программы является движение назад, требующее восстановления последнего варианта предыдущего хода. Эта задача автоматически решается при рекурсивной организации программы. Поэтому алгоритмы с возвратом наиболее естественно выражаются в терминах рекурсии. Однако в этом случае при движении назад возрастает объем переписываемой информации, что снижает скорость работы программы.

7.4. Алгоритмы ветвей и границ
Алгоритмы применяется для решения переборных задач. Они исследуют древовидную модель пространства решений и ориентированы на поиск оптимального решения из конечного множества возможных решений-вариантов. Рассмотрим задачу, в которой алгоритм ветвей и границ хорошо работает и прост в понимании.
Задача о коммивояжере. Дано множество городов, пронумерованных от 0 до N. Варианты проезда задаются графом. Пути между парами городов характеризуются некоторой величиной, например, стоимостью или временем проезда, расходом горючего и т.д. Требуется проложить замкнутый путь – тур, который проходит через все города, двигаясь по которому каждый город проходится только раз, и при этом суммарная характеристика тура минимальна, например, минимальна стоимость проезда по всему туру.
Рассмотрим задачу на примере пяти городов с заданной матрицей стоимостей проезда.
Если стоимость обратного и прямого проездов для пары городов одинакова, то матрица стоимостей будет симметричной. В примере взят общий случай, когда стоимости прямого и обратного проезда не совпадают. Поставленная задача просто решается путем конечного перебора вариантов тура.
Множество туров таково:
1. 1(2(3(4(5(1 2. 1(2(3(5(4(1 3. 1(2(4(3(5(1
4. 1(2(4(5(3(1 5. 1(2(5(3(4(1 6. 1(2(5(4(3(1
7. 1(3(2(4(5(1 8. 1(3(2(5(4(1 9. 1(3(4(2(5(1
10. 1(3(4(5(2(1 11. 1(3(5(4(2(1 12. 1(3(5(2(4(1
13. 1(4(2(3(5(1 14. 1(4(2(5(3(1 15. 1(4(3(2(5(1
16. 1(4(3(5(2(1 17. 1(4(5(2(3(1 18. 1(4(5(3(2(1
19. 1(5(2(3(4(1 20. 1(5(2(4(3(1 21. 1(5(3(2(4(1
22. 1(5(3(4(2(1 23. 1(5(4(2(3(1 24. 1(5(4(3(2(1
Для полносвязной сети-графа (каждый связан с каждым) количество всевозможных туров равно (N-1)! (для N=5 число туров 24). При больших N быстро растет и число туров и потребуется огромное количество вычислений, если использовать схему полного перебора всех вариантов. Поэтому важен алгоритм, позволяющий сократить число переборов. Но прежде рассмотрим способ организации полного перебора туров. Для этого воспользуемся алгоритмом с отходом назад из предыдущего параграфа. Рассматриваемый способ полного перебора позволяет произвести перебор вариантов и в случае неполносвязной сети, когда некоторые недиагональные элементы матрицы стоимостей равны бесконечности или отсутствует соответствующий переезд.
В исходной матрице (матрица X – см. дерево полного перебора) выбирается стоимость, не равная бесконечности, которая принимается за базу ветвления. База ищется по следующему правилу. В матрице стоимостей ищется строка i, имеющая не менее двух стоимостей < (, и среди них за базу берется та стоимость Cij((, у которой наименьший индекс j. В нашем примере – это C12. Затем производится ветвление, которое заключается в построении по исходной матрице двух новых матриц стоимостей. Суть ветвления заключается в разбиении исходной задачи на две подзадачи. В первой подзадаче, соответствующей первой матрице, фиксируется базовый переезд. Любой тур в этой подзадаче будет содержать фиксированный переезд (i,j), что означает переезд из города i только в город j и более ни в какой, а также переезд в город j только из города i. Это отражается в матрице приравниванием элементов строки и столбца, содержащих базу, бесконечности. Также посредством приравнивания бесконечности симметричного базе элемента запрещается обратный переезд из города j в город i, так как в противном случае не будет полного тура. Во второй подзадаче, соответствующей второй матрице, наоборот запрещается базовый переезд, что отражается приравниванием бесконечности базового элемента. Таким образом, ветвление от базы приводит к построению двух матриц, в каждой из которых затем вновь устанавливается база, и задача опять разбивается на две подзадачи.
Первая матрица (матрица A). Приравниваются бесконечности стоимости, находящиеся в строке и столбце базы C12 (C13=C14=C15=(, C32=C42=C52=(), и симметричная базе стоимость C21=(. Значение базы не изменяется. Производится предотвращение циклов (описание ниже) и проверка полученной матрицы на наличие элемента, являющегося единственным не равным бесконечности элементом строки (столбца), и в то же время не являющегося таковым в столбце (строке). Если такого элемента нет, то матрица построена. В противном случае найденный элемент выбирается за базу и повторяется процедура ветвления от новой базы.
Вторая матрица (матрица B). Замена базового элемента на бесконечность (C12=(). Выбор нового базового элемента и повторение процедуры, аналогичной построению первой матрицы.
Предотвращение циклов. Для пояснения смысла этой операции рассмотрим процесс построения матрицы C из матрицы A. Базовым элементом является C23. Тогда полагаем C24=C25=C43=C53=(, остальные уже равны бесконечности. При этом фиксировано два переезда 1(2 и 2(3. Переезд из 3 в 2 запрещен (C32=(), но осталась еще одна возможность возникновения цикла переезд 3(1, при использовании которого получим цикл 1(2(3(1, что противоречит условию задачи – тур должен быть полным. Поэтому следует положить C31=(. Формализуя процесс предотвращения циклов, получим. Пусть Cij - база. Приравниваем ее бесконечности (Cij=(). Проверяем столбец i, если найден элемент Cki такой, что является единственным, не равным бесконечности в строке, то полагаем Ckj=(. Таким же образом обрабатываем столбец k и, если соответствующий элемент не найден, завершаем процесс предотвращения циклов. Иначе продолжаем проверку.
Матрицы, полученные в результате ветвления, на следующих шагах рассматриваются в качестве исходных, и с ними производятся описанные выше операции, что приводит к построению дерева (см. рис.), листьями которого являются матрицы, описывающие все 24 тура. Стоимости туров определяются суммой конечных элементов матрицы.
Таким образом, определен полный перебор вариантов, и можно перейти к описанию собственно алгоритма ветвей и границ - определению процесса вычисления границ, являющегося второй компонентой задачи (организация ветвления – первая компонента). В алгоритме вычисления границ рассчитываются нижние границы, для каждой из возникающих подзадач – матриц в дереве перебора. Основной шаг при вычислении границ называется приведением, и оно основано на следующих утверждениях.
Тур содержит только один элемент из каждых столбца и строки матрицы стоимостей. Если вычесть константу из каждого элемента некоторой строки (столбца), то стоимость каждого тура во вновь полученной матрице ровно на эту константу меньше стоимости того же тура в исходной матрице. Процесс приведения для каждой строки предполагает поиск минимального элемента, его вычитание из стоимостей строки и проведение аналогичных действий со столбцами (см. рис.).
Сумма констант приведения (13 EMBED Equation.3 1415) есть нижняя граница стоимости любого тура задачи. На ветвление процесс приведения практически не влияет за исключением выбора базовых элементов. В качестве кандидатов на роль базовых элементов рассматриваются элементы равные нулю (C12, C21, C34, C35, C41, C53, C54). Среди них за базовый принимается элемент, имеющий максимальную сумму минимальных элементов по строке и столбцу, в которых он расположен. Так, для нашей приведенной матрицы имеем.
Для C12: C14=MinC1j=4, j(2; C52=MinCi2=6, i(1. (=10.
Для C21: C23=MinC2j=8, j(1; C41=MinCi1=0, i(2. (=8.
Для C34: C34=MinC3j=0, j(4; C45=MinCi4=1, i(3. (=0.
Для C35: C35=MinC3j=0, j(5; C54=MinCi5=0, i(3. (=1.
Для C41: C45=MinC4j=1, j(1; C21=MinCi1=0, i(3. (=1.
Для C53: C54=MinC5j=0, j(3; C23=MinCi3=8, i(3. (=8.
Для C54: C53=MinC5j=0, j(4; C34=MinCi4=0, i(3. (=0.
Максимальная сумма соответствует элементу C12, он и принимается как базовый. Далее производится ветвление (см. рис. "Ветвление").
Строится первая матрица ветвления, производится ее приведение, и сумма констант приведения суммируется к уже имеющейся нижней границе, равной 48, что дает 56 как нижнюю границу стоимости любого тура в данной подзадаче. Этот процесс продолжается до получения первого тура и его стоимости, после чего производится возврат на шаг вверх по дереву и исследование ветвей, порождаемых движением вниз, т.е. ветвей порождаемых вторыми матрицами процесса ветвления (на данном рисунке в отличие от предыдущего первые матрицы ветвления изображаются справа от порождающей матрицы). Ветвь не имеет смысла исследовать, если нижняя граница для туров в данной подзадаче превышает стоимость наилучшего пути, найденного в данный момент. Как видно из рисунка, все ветви в дереве, идущие вниз, имеют нижние границы, превышающие стоимость тура 1(2(3(5(4(1, равную 56. Следовательно, это и есть искомый тур задачи. Рассмотренный пример показывает, как много вариантов в ряде случаев удается исключить из рассмотрения.
Алгоритм ветвей и границ является одним из наиболее эффективных методов решения ряда переборных задач. Как правило, эти алгоритмы сложны для понимания, но выигрыш, получаемый в результате их применения, стоит тех усилий, которые приходится затратить на разработку собственного алгоритма или на понимание готового алгоритма.





Тема 8
Алгоритмы сортировки
8.1. Сортировка. Основные понятия
Пусть задан (-файл, состоящий из записей 13 EMBED Equation.3 1415. Припишем каждой записи 13 EMBED Equation.3 1415 ключ 13 EMBED Equation.3 1415. Ключ – какое-либо отдельное поле или комбинация полей записи. Часто запись целиком составляет поле ключа. Будем считать, что на множестве ключей задано отношение линейного порядка или следования с обычными свойствами, т.е. элементы этого множества можно выстроить в порядке не убывания (не возрастания). Задача сортировки файла ставится так.
Найти такую перестановку записей (-файла, чтобы в (-файле для записей 13 EMBED Equation.3 1415 их ключи располагались в неубывающем порядке: 13 EMBED Equation.3 1415.
Для получения (-файла из (-файла в общем случае требуется физическое перемещение записей в памяти компьютера. Однако во многих случаях реальная перестановка не требуется. Достаточно описать ее некоторым способом так, чтобы обеспечить непосредственный доступ к записям в соответствии следованию их ключей. Сделать это можно посредством адресного кодирования или адресной перестановки, в которой сортируются индексы (адреса) элементов-записей, а не сами записи. Правда в этом случае под адреса требуется дополнительная память. Часто адресное кодирование применяется в качестве первого этапа для обычной сортировки.

Ф. И. О.
Курс
Предмет
Тип задолженности

1
2
3
4
5
6
7
Щукина Э.
Паниковский М.С.
Бендер О.И.
Синицкая З.В.
Воробьянинов И.М
Востриков Ф
Изнуренков А.В.







Алгебра
Физика
Физика
Геометрия
Алгебра
Физика
Алгебра
Зачет
Экзамен
Зачет
Экзамен
Экзамен
Зачет
Зачет

Пример 1. В таблице приведен текстовый файл из 7 записей. Запись состоит из 5 полей. Адресное кодирование файла в алфавитном порядке фамилий студентов производится посредством списка: 3, 5, 6, 7, 2, 4, 1. Этот список можно использовать для реального перемещения записей в файле задолжников.
Различают внутреннюю сортировку данных в памяти компьютера и внешнюю сортировку данных, расположенных на диске. При внутренней сортировке стремятся уменьшить число сравнений ключей и перемещений записей, а при внешней сортировке – количество обращений к диску. В дальнейшем будем ориентироваться на внутреннюю сортировку числовых и символьных одномерных массивов. Записями и ключами таких файлов-массивов будем считать значения их элементов.
Пример 2. Отсортировать числовой массив: 7,2 3 8 4 8 5,14 9 1.
Обычная сортировка: 1 3 4 5,14 7,2 8 8 9.

8.2. Пузырьковая сортировка
Среди большого числа сортировок наиболее популярна пузырьковая сортировка. Ее название происходит от образной интерпретации всплывания более легких элементов (пузырьков) на поверхность.
Пусть S числовой массив 13 EMBED Equation.3 1415. Говорят, что элементы 13 EMBED Equation.3 1415 и 13 EMBED Equation.3 1415 из S образуют инверсию, если i < j и 13 EMBED Equation.3 1415.
Алгоритм пузырьковой сортировки состоит в последовательных просмотрах снизу вверх (от конца к началу) массива S и обмене местами соседних элементов с инверсией. Трудоемкость алгоритма - O(n2), т.е. для любых S и n он решает задачу за C(n2 операций сравнения и обмена, где C -константа, от n не зависящая.
Пузырьковая сортировка не требует дополнительной памяти, однако из-за плохих временных характеристик она имеет лишь исторический интерес. Практический интерес представляют две наиболее эффективных сортировки Пирамидальная и Быстрая.
8.3. Сортировка с помощью дерева
Все способы сортировок основаны на многократном просмотре массива записей и выполнении определенных операций над ними. Можно ли улучшить временные характеристики сортировок? Ответ положителен, если за единичный просмотр массива извлекать больше информации. Для этого следует сортируемый массив S представить в виде нелинейной структуры типа двоичного (бинарного) дерева D. На рисунке показан такой граф D для массива S из n<16 элементов. В кружках размещены элементы массива: 9 14 8 1 5 4 9 12 3 17 1 3. Натуральными числами, начиная от 1, сверху вниз по уровням и слева направо на одном уровне пронумерованы все вершины дерева. Эти номера (адреса) проставлены около вершин.
13 SHAPE \* MERGEFORMAT 1415
У бинарного дерева имеется только один корневой узел, для которого нет предшественников – родителей. Адрес корня – 1. Любой другой узел имеет только одного предшественника и одного или двух преемников – потомков. Иногда деревья изображают в виде двумерного массива с явным указанием адресов родителей и потомков для каждого узла k (k=1(n). Однако на практике эти адреса лучше не хранить, а вычислять по формулам
родитель: 13 EMBED Equation.3 1415,
потомок слева: 13 EMBED Equation.3 1415, потомок справа: 13 EMBED Equation.3 1415.
Любой узел дерева может быть корнем другого дерева – поддерева, именуемого номером узла, выбранного в качестве его корня.
Описанное представление массива S в форме бинарного дерева D, используется для построения алгоритма пирамидальной сортировки. Здесь же рассмотрим родственное представление массива S и некоторой дополнительной информации для него в форме дерева. Это позволит уяснить серию бинарных или турнирных сортировок. Пусть элементы массива S размещены в узлах нижнего уровня D. Тогда отсортировать массив можно в два этапа, называемых построением исходного дерева и непосредственной сортировкой.
Этап 1. На первом шаге посредством n/2 сравнений пар элементов массива S определяется элемент с меньшим значением, который переводится на следующий уровень и становится общим родителем пары. На втором шаге за не более, чем n/4+1 сравнений, находятся наименьшие элементы для родительских пар и переводятся на следующий уровень родителей для родительских пар и т.д. В общем случае построение дерева выбора, корнем которого окажется наименьший элемент массива, потребуется всего n-1 сравнений.
13 SHAPE \* MERGEFORMAT 1415
Этап 2. Элемент с наименьшим значением (, поднявшийся до корня дерева, объявляется очередным элементом отсортированного массива. Производится спуск по пути, им обозначенному при подъеме вверх по дереву. При наличии нескольких таких путей вниз предпочтение отдается тем, которые включают потомков слева. Элемент с наименьшим значением ( на нижнем уровне D исключается ((=() и производится дополнительное сравнение элементов для пройденного пути наверх. При этом в корень дерева выходит следующий элемент с наименьшим значением и т.д. (см. рис.). После n-кратного выполнения этапа дерево D будет состоять из значений (, процесс сортировки на этом завершается. Для однократного прохода этапа требуется выполнить log2 n сравнений.
Общая трудоемкость турнирной сортировки составляет O(n log2 n), операций. Алгоритмы этого типа сортировки отличаются способом представления исходной и сопутствующей информации, объемом дополнительной памяти и т.п.
8.4. Пирамидальная сортировка
Алгоритм пирамидальной сортировки предложен Уильямсом и развит Флойдом. Алгоритм основан на бинарном дереве, не требует дополнительной памяти и имеет трудоемкость O(n log2 n).
Пусть задан массив 13 EMBED Equation.3 1415. (1)
Пирамидой называется непустая последовательность элементов (1) вида
13 EMBED Equation.3 1415, (2)
для которой выполнено одно из условий 13 EMBED Equation.3 1415.
Из определения вытекают следующие утверждения.
1). Для любой последовательности (1) последовательность 13 EMBED Equation.3 1415 является пирамидой.
2). Если последовательность (1) – пирамида, то выполняется условие 13 EMBED Equation.3 1415. (3)
3). Если последовательность (1) – пирамида и представлена в виде бинарного дерева, то значение любого узла в нем будет не меньше значений его левого и правого потомков.
Пример 1. Последовательность чисел:
90 70 11 8 3 9 7 5 6 1 2
является пирамидой. Наглядно это видно из рисунка.
Алгоритм реализуется в два этапа.

Этап 1. Построение пирамиды
Имеем последовательность 13 EMBED Equation.3 1415, являющейся пирамидой. Нарастим ее слева элементом 13 EMBED Equation.3 1415. Тогда получим последовательность 13 EMBED Equation.3 1415, (4)
которую снова преобразуем в пирамиду. Для этого "просеем" 13 EMBED Equation.3 1415 по соответствующей веточке двоичного представления (1). Для этого рассмотрим 13 EMBED Equation.3 1415 и два его потомка 13 EMBED Equation.3 1415 и 13 EMBED Equation.3 1415. Если 13 EMBED Equation.3 1415 не меньше потомков, то вычисления прекращаем, так как (4) уже пирамида, в противном случае обмениваем значения 13 EMBED Equation.3 1415 и 13 EMBED Equation.3 1415 в соответствующих позициях дерева, а "опустившийся" элемент продолжаем просеивать тем же способом, пока (4) не станет пирамидой. Продолжаем наращивать последовательность (4) пока последовательность (1) не станет пирамидой. При этом будет выполнено условие (3). Построенная пирамида объявляется S-текущей.
Этап 2. Сортировка пирамиды
В S-текущей пирамиде первый элемент не меньше остальных. Обменяем значениями концевые элементы массива S и укоротим его справа на 1. Полученная последовательность может и не быть пирамидой. Применяя к ней процесс "просеивания" для элемента 13 EMBED Equation.3 1415, описанный выше, преобразуем последовательность в пирамиду. Повторяя этап (n-1) раз, отсортируем массив S по не возрастанию.
Этап 1. Построение пирамиды
Этап 2. Сортировка пирамиды

23
77
12
7
44
82
16
53
7
77
23
53
44
12
16
82

23
77
12
53
44
82
16
7
16
53
23
7
44
12
77
82

23
77
82
53
44
12
16
7
12
44
23
7
16
53
77
82

23
77
82
53
44
12
16
7
12
16
23
7
44
53
77
82

82
77
23
53
44
12
16
7
7
16
12
23
44
53
77
82









12
7
16
23
44
53
77
82









7
12
16
23
44
53
77
82

Пример 2. Для последовательности чисел: 23 77 12 7 44 82 16 53 произвести пирамидальную сортировку, выписывая текущие последовательности в процессе выполнения алгоритма. В строках таблицы показаны значения массива после каждой реализации этапов. При этом в этапе 1 ступенчатая линия отделяет остаток последовательности от наращиваемой слева пирамиды, а в этапе 2 – сокращаемую справа последовательность перед просеиванием ее первого элемента от формируемого с конца отсортированного массива.

Анализ пирамидальной сортировки показывает, что для ее выполнения требуется не более 3 n log2 n элементарных операций типа сравнения и обменов. Высокая эффективность обеспечивает популярность алгоритму. Ниже приведена программа сортировки по не убыванию одномерного массива, заполненного случайными числами.
8.5. Быстрая сортировка
В пузырьковой сортировке производились обмены ключей (записей) в соседних позициях. В пирамидальной сортировке такие обмены совершались между ключами в позициях, связанных друг с другом бинарным деревом. Алгоритм сортировки Хоора или сортировки с разделение или быстрой сортировки использует иной механизм выбора значений для обменов. В названиях алгоритма подчеркиваются автор, или способ сортировки – последовательного дробления массива на части, или его эффективность. В подавляющем большинстве случаев быстрая сортировка дает лучшие временные результаты по сравнению с другими способами. Однако для нее нет гарантированной трудоемкости типа O(n log2 n), а в отдельных случаях ее трудоемкость достигает O(n2) и не может быть снижена. В ситуациях жесткого временного ограничения сортировку следует применять весьма осмотрительно.
Суть способа. Пусть 13 EMBED Equation.3 1415 – одномерный массив, а x – его элемент. Сначала выясним, как разбить массив S на две непустые непересекающиеся части S1 и S2 (S1( S2=S) так, чтобы в S1 оказались элементы, не превосходящие x , а в S2 – не меньше x: 13 EMBED Equation.3 1415. Для этого рассмотрим пример. Пусть в массиве S зафиксирован элемент x=14. Просматриваем массив слева направо, пока не найдем 13 EMBED Equation.3 1415. 13 EMBED Equation.3 1415. Просматриваем массив справа налево, пока не найдем 13 EMBED Equation.3 1415. 13 EMBED Equation.3 1415. Меняем местами a и b. Продолжая этот процесс, придем к последовательности, разделенной на две части S1 и S2:
Обозначим через p позицию разделения массива. Элементы от 1-го до p-го включительно относятся к S1, а остальные – к S2. Значение x для разделения будем выбирать из середины массива. При четном числе элементов имеются два кандидата на роль x, из них берем элемент с меньшим индексом. Если, аналогично рассмотренному разбиению, продолжить этот процесс для полученных частей массива, а затем и для частей вновь полученных частей, то в конечном итоге получим отсортированный массив. Но при этом необходимо хранить адреса разделяемых частей массива. Если после очередного разбиения продолжать работу с меньшей из полученных частей, отправляя на хранение адреса начала и конца второй части, то потребуется немного дополнительной памяти – не более 13 EMBED Equation.3 1415 адресов (для n(4000 число адресов не более 12).
Выше приведена программа быстрой сортировки. В ней хранение адресов организовано в виде наращиваемого стека, выборка из которого производится в порядке, обратном занесению, т.е. последняя часть массива, адреса которой внесены в стек, обрабатывается первой. Сортировка идет в порядке возрастания значений элементов массива. При этом левая часть раздвоенной сортируемой последовательности сразу идет в дальнейшую обработку, а правая в виде начального и конечного адресов – сохраняется в стеке. Таким образом, в стеке сохраняются правые части раздвоенных ссужающихся последовательностей. Левая часть ссужающихся последовательностей обрабатывается до тех пор, пока ее границы не сомкнутся – последовательность вырождается в один элемент. Самым сложным моментом в алгоритме является анализ граничных ситуаций между частями последовательности – совместный анализ правой границы левой части и левой границы правой части. Выделяются четыре вида таких ситуаций.
1). Перехлест, когда правая граница левой части перешла левую границу правой части, но проходит по соседним элементам – раздвоение границ. Данная ситуация возникает, когда границы в результате своего движения синхронно подходят к двум соседним элементам слева и справа и при этом значения элементов располагаются по обе стороны выбранного уровня разделения (переменная x в программе) – левый элемент ниже уровня, а правый элемент выше уровня.
2). Смыкание, когда границы накладываются друг на друга, т.е. проходят по одному и тому же элементу. Ситуация возникает, когда границы синхронно подходят к элементу, значение которого совпадает с выбранным уровнем разделения.
3). Четкое разделение – границы не смыкаются, т.е. приходятся на соседние элементы.
4). Люфт, когда между границами располагается один непроанализированный элемент.
Следует отметить, что в отличие от первых двух ситуаций, возникающих в результате нерегулируемого движения границ (индексы i и j в программе), две последние ситуации организуются целенаправленно. Каждая из этих ситуаций должна быть проанализирована и в каждом случае должны быть вставлены регуляторы границ, чтобы привести их к четкому единому разделению. Для этого используется анализ элемента в ситуации люфта и передвижка границ, как в этой ситуации, так и при их перехлесте и смыкании.

Тема 9
Алгоритмы поиска и перебора
9.1. Поиск. Основные понятия
С задачами поиска информации человеку приходиться сталкиваться постоянно. Типичными примерами служит поиск по справочникам, телефонной книге, картотеке и т.д. Полагаем, что файл ( состоит из записей 13 EMBED Equation.3 1415 с ключами 13 EMBED Equation.3 1415 и пусть K – значение ключа. Различают четыре варианта простейших задач.
1). Требуется определить, по крайней мере, одну запись из (-файла, имеющую своим ключом K.
2). Определить все записи из (-файла, имеющие K своим ключом.
3). Если в (-файле нет записей с ключом K, то добавить новую запись.
4). Включить в (-файл новую запись.
K называется аргументом поиска или запросом, первые две задачи простым статическим поиском, а последние две – динамическим поиском со вставкой. Иногда в трех первых задачах поиск организуется не по ключу, а по выполнению некоторых условий для определенной функции от ключей. Примером может служить поиск по интервалу значений ключа, когда отыскиваются записи 13 EMBED Equation.3 1415 с условиями: 13 EMBED Equation.3 1415, где a и b – константы. Методы поиска классифицируются по местонахождению и изменению (-файла, схеме доступа к отдельным записям 13 EMBED Equation.3 1415, способу сравнения ключей или функций от них и т.п. Например, поиск называется внутренним, если (-файл целиком размещается в оперативной памяти, и внешним – в противном случае. Здесь мы будем рассматривать только внутренний поиск. Под файлом будем понимать одномерный или двумерный числовой или символьный массив, и поиск вести в одномерной или двумерной таблице.
Различные варианты задач поиска встречаются при решении других проблем, например, в сортировках, где постоянно приходиться искать пары для текущих обменов. От организации исходной информации во многом зависит эффективность алгоритмов поиска. И в этом контексте сортировки играют полезную роль в предварительном преобразовании (-файла. В различных информационных системах поиск требует наибольших временных затрат. Поэтому эффективность их программного обеспечения прямо зависит от типа используемого алгоритма поиска.
9.2. Бинарный поиск
Наиболее простым способом поиска является последовательный поиск, в котором производится просмотр подряд всех записей (-файла до получения решения задачи. Рассмотрим наиболее употребительный и эффективный способ поиска в упорядоченном массиве. Этот способ имеет несколько названий – бинарный, логарифмический поиск, способ деления пополам. Идея бинарного поиска проста. Ключ сравнивается со значением среднего ключа таблицы. Результат сравнения или приводит к решению задачи, или позволяет определить, в какой части массива (верхняя, нижняя) продолжать поиск. Применяя описанный процесс к наполовину укороченному массиву посредством не более чем log2 n сравнений, получим позитивное или негативное решение. Ниже приводится программа бинарного поиска.
9.3. Поиск в сети
Пусть задана ориентированная сеть 13 EMBED Equation.3 1415 (см. рис.), где P –множество вершин, R – множество дуг, d – функция, определенная на множестве R со значениями во множестве действующих чисел. Иногда 13 EMBED Equation.3 1415 интерпретируют как длину дуги 13 EMBED Equation.3 1415. В алгоритмах оптимизации на сетях во внутренних циклах многократно приходится решать две задачи.
1). Для фиксированной вершины 13 EMBED Equation.3 1415 определить все дуги сети вида 13 EMBED Equation.3 1415 – выходы из x.

Дуги
d


x
y


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
7
3
5
9
4
8
3
7
1
1
6
1
6
6
6
8
4
9
5
5
9
6
6
3
7
4
6
8
5
9
3
4
1
3
2
1
1
1
3
2
2
5
3
5
2

2). Для фиксированной вершины 13 EMBED Equation.3 1415 определить все дуги сети вида 13 EMBED Equation.3 1415 – входы в x.
В больших сетях алгоритмы с простым перебором всех элементов из R, для поиска дуг, выходящих или входящих из/в x, естественно, не эффективны. Рассмотрим один из способов ускорения поиска в сети. Будем считать, что сеть представлена в оперативной памяти в виде массива дуг (, как это показано в таблице, и что записями являются отдельные строки.
Пусть вначале решается первая задача. Отсортируем (-файл по ключу x. Ясно, что среднее время нахождения всех дуг 13 EMBED Equation.3 1415 даже при последовательном поиске сократится примерно наполовину. Кроме того, становится возможна организация более эффективного бинарного поиска. Однако рассмотрим иной подход. Пусть имеется некоторый вспомогательный массив A, в позициях x которого записан адрес 13 EMBED Equation.3 1415 расположения в (-файле начальной дуги вида 13 EMBED Equation.3 1415. В этом случае поиск всех дуг сводится к выборке адреса 13 EMBED Equation.3 1415. Если, например, требуется найти в (-файле все дуги вида 13 EMBED Equation.3 1415, то получив 13 EMBED Equation.3 1415, сразу попадаем на требуемое подмножество выходов из вершины 6 (рис. справа) в массиве. Описанный способ решения задачи предполагает, что 13 EMBED Equation.3 1415 – это натуральные числа. При этом для минимизации объема дополнительной памяти, т.е. величины 13 EMBED Equation.3 1415, желательно иметь последовательную нумерацию вершин, начиная с 1. Символ ( указывает на отсутствие вершины с данным номером.
Перейдем ко второй задаче. Если отсортировать (-файл по y, то аналогично строится простой механизм поиска входов в вершины. Однако при этом теряется возможность эффективно решать первую задачу. Вводим в рассмотрение два вспомогательных одномерных массива 13 EMBED Equation.3 1415 и 13 EMBED Equation.3 1415. Пусть 13 EMBED Equation.3 1415 устроен так же, как и 13 EMBED Equation.3 1415. В позиции x массива 13 EMBED Equation.3 1415 указывается адрес ( первой от начала строки в (-файле с дугой 13 EMBED Equation.3 1415. Далее, если по некоторому адресу ( записана дуга 13 EMBED Equation.3 1415, то в 13 EMBED Equation.3 1415 указывается адрес в (-файле следующей такой дуги. Символ ( в массиве 13 EMBED Equation.3 1415 используется для указания отсутствия входов в вершину x, а в массиве 13 EMBED Equation.3 1415 – как метка завершения соответствующего множества входов. При такой организации 13 EMBED Equation.3 1415 и 13 EMBED Equation.3 1415 поиск всех входов в x сводится к выборкам сначала адреса 13 EMBED Equation.3 1415, а затем последовательных адресов из массива C (рис. слева).
Формирование массивов B и C приводит к адресному кодированию (-файла, т.е. проводится адресная сортировка (-файле по y. Для рассмотренной ранее схемы поиска выходов дуг из вершин можно было бы отказаться от начальной сортировки (-файла по x, заменив ее подобным адресным кодированием. Но при этом пришлось бы добавить еще один вспомогательный массив, устроенный аналогично C и используемый для хранения последующих адресов. Массивы A, B и C называются справочниками, а их совокупность – справочной (-файла. Таким образом, чтобы адресовать записи (-файла, необходимо построить справочники: 1) A, 2) B и C, 3) A, B и C. Сделать это несложно, при этом после сортировки все организуется за один просмотр (-файла. Ниже приводятся три программы, формирующие три указанные типы справочной (-файла.
Справочник A. Адреса выходов из вершин.
Справочники B и C. Адреса входов в вершины.
Справочники A, B и C. Адреса входов и выходов в/из вершин.
9.4. Генератор перестановок
Иногда задачу приходиться решать полным перебором всех вариантов, если нет иного пути. В подобных случаях полезен алгоритм получения всех n! перестановок из множества 13 EMBED Equation.3 1415, где 13 EMBED Equation.3 1415 – попарно различные действительные числа. Пошаговый алгоритм выглядит так.
Шаг 1. Отсортируем последовательность 13 EMBED Equation.3 1415 в порядке убывания и полученную перестановку считаем начальной.
Шаг 2. Находим наименьший индекс 13 EMBED Equation.3 1415, при котором 13 EMBED Equation.3 1415.
Шаг 3. Находим наименьший индекс 13 EMBED Equation.3 1415, при котором 13 EMBED Equation.3 1415.
Шаг 4. Обмениваем значениями 13 EMBED Equation.3 1415 и 13 EMBED Equation.3 1415.
Шаг 5. Обмениваем значениями компоненты в парах 13 EMBED Equation.3 1415, где 13 EMBED Equation.3 1415.
Шаг 6. Фиксируем очередную перестановку и если их количество меньше n!, то переходим к шагу 2. В противном случае останавливаемся.
Покажем, что, используя приведенный алгоритм, получим все n! различных перестановок. Не ограничивая общность, полагаем, что последовательность состоит из натуральных чисел 1, 2, (, n. Зафиксируем 13 EMBED Equation.3 1415 и рассмотрим t-ричную систему счисления с цифрами 0, 1, 2, (, n, (, t-1. Во множестве B n-значных t-ричных чисел выделим подмножество B0 чисел, у которых цифры попарно различны и являются элементами последовательности S. Перестановки из последовательности S и элементы подмножества B0 можно поставить во взаимно однозначное соответствие по правилу
13 EMBED Equation.3 1415.
Следовательно, проблема получения всех перестановок из последовательности S является задачей выделения во множестве B подмножества B0. Пусть элементы подмножества B0 выписаны в порядке возрастания 13 EMBED Equation.3 1415. Тогда шаг 1 алгоритма определяет первоначальную перестановку 13 EMBED Equation.3 1415, соответствующую числу 13 EMBED Equation.3 1415. Если уже сгенерирована перестановка 13 EMBED Equation.3 1415, то совокупность шагов 3-6 формирует перестановку, соответствующую числу 13 EMBED Equation.3 1415. Этим доказывается, что будут получены все n! перестановок из последовательности S.
Функция n! растет очень быстро. Например, число различных списков из десяти различных фамилий равно 3628800, поэтому практическое использование алгоритма перестановок весьма ограничено. Ниже приводится программа генератора перестановок.
Продемонстрируем работу генератора перестановок на типичной задаче коммивояжера, которая была рассмотрена в алгоритме ветвей и границ. Вновь приведем ее формулировку. Коммивояжер (агент по сбыту), отправляясь из своего города, должен кратчайшим маршрутом посетить по одному разу n-1 заданных городов и вернуться назад. Естественно, для больших n необходимо использовать эффективный метод ветвей и границ. Для небольших n будем решать эту задачу перебором всех возможных замкнутых маршрутов, проходящих по одному разу через каждый из городов. Будем называть такие маршруты допустимыми. Пусть города пронумерованы числами 1, 2, (, n, расстояния между ними равны 13 EMBED Equation.3 1415, причем значения 13 EMBED Equation.3 1415 и 13 EMBED Equation.3 1415 могут не совпадать. При отсутствии маршрута (дороги) между пунктами i и j можно считать, что 13 EMBED Equation.3 1415. Всякая перестановка 13 EMBED Equation.3 1415 из элементов 1, 2, (, n определяет допустимый маршрут: Тогда для решения задачи коммивояжера, перебирая все возможные перестановки 13 EMBED Equation.3 1415, достаточно вычислить длины соответствующих маршрутов и запомнить лучшие из них. Причем учитываются только те перестановки, в которых 13 EMBED Equation.3 1415, ввиду замкнутости маршрутов. Таким образом, для n городов просматриваются и анализируются (n-1) маршрутов. Ниже приведена программа задачи коммивояжера.


Тема 10
Событийно-управляемое программирование на языке Visual Basic
10.1. Историческая справка
Язык BASIC - универсальный символьный программный код для начинающих был создан в начале 60-х годов в Dartmouth College. Важнейшие его качества – простота и компактность – оказались решающими в период перехода на микрокомпьютеры. В 1975 году появились первые "Альтаиры", возвестившие о наступлении новой эпохи. Билл Гейтс и Пол Ален, основатели корпорации Microsoft создали версию BASIC для "Альтаира", способную работать в 4 Кб оперативной памяти этого компьютера. Со временем эта версия превратилась в один из самых популярных программных продуктов для персональных компьютеров.
Шли годы, BASIC совершенствовался и развивался. И когда маломощные микрокомпьютеры уступили место персональным IBM PC, стандартом для них стал GW-BASIC. Впоследствии потребность в более быстром, компактном и простом в работе языке привела к появлению Microsoft QuickBasic. Хотя новая версия и подняла BASIC на уровень технологии программирования 80-х годов, в компьютерном мире наметились большие перемены ( переход на стандарт графического интерфейса пользователя (GUI). Внедрение графического способа отображения информации значительно увеличило объемы отображаемой на дисплее информации, сделало работу с компьютером более понятной и комфортной. Кроме аппаратной поддержки для реализации графического интерфейса потребовалась и соответствующая программная поддержка. Наиболее удачной была разработанная фирмой Microsoft операционная система Windows.
С появлением Windows пользователи персональных компьютеров (ПС) получили возможность работать в графической, интуитивно понятной среде. Интерфейс GUI не только значительно упростил обучение навыкам работы с программами (приложениями), но и саму работу. Вместо набора на клавиатуре команд MS DOS теперь достаточно было одним нажатием кнопки мыши выбрать в меню нужный пункт. Многооконный режим позволял работать сразу с несколькими программами.
С появлением Windows пользователи выиграли, но работа программистов усложнилась. Теперь им даже в самом простом приложении приходилось создавать и программировать окна, меню, шрифты, диалоговые окна и множество других элементов. Программисты испытывали двойственные чувства: интереса ( потому что Windows предоставила платформу для написания графических приложений с "дружественным" интерфейсом, и досады, поскольку вырос объем работы. Так, простую программу, которая выводит на экран некоторое сообщение, программист в операционной системе MS-DOS мог составить из четырех строк кода. Аналогичная программа под Windows уже требует минимум двух, а то и трех страниц кода ( не говоря уже о контроле шрифтов, меню, окон, памяти и других системных ресурсов. Но преимущества Windows для конечного пользователя оказались настолько неоспоримы, что профессиональным программистам пришлось смириться с этой.
В 1991 году корпорация Microsoft представила первую версию системы программирования Visual Basic, которая позволила сблизить любительское и профессиональное программирование. Эта система позволила отстраниться от сложной внутренней структуры Windows и творить в свое удовольствие. Сочетание расширенных возможностей BASIC со средствами визуального проектирования упростило процесс программирования, не жертвуя при этом производительностью или использованием графических функций. Меню, шрифты, диалоговые окна, списки с прокруткой текста и прочее легко создаются несколькими строками программного кода. Язык Visual Basic ( один из первых языков, поддерживающий событийно-управляемое программирование.
Этот стиль хорошо согласуется со стандартом GUI. Традиционное программирование ориентировалось на поэтапное описание конкретного процесса, поэтому программный код во многом напоминал кулинарный рецепт: "взять три яйца, стакан молока, добавить сахар, перемешать и поставить в духовку на 20 минут". Один из недостатков такого стиля очевиден ( тот, кто составляет рецепт (т.е. программу), должен все делать сам. При разработке современных компьютерных приложений (программных средств) с этим примириться уже нельзя. Основной смысл событийно-управляемого программирования в том, что вместо скрупулезного описания каждого шага Вы лишь указываете, как реагировать на различные события (действия пользователя). Вы создаете не одну большую программу, а приложение, состоящее из набора взаимодействующих микропрограмм (процедур), управляемых пользователем. С помощью Visual Basic такое приложение можно разработать быстро и без особых усилий. Система программирования, основанная на Visual Basic, как и сам язык, постоянно развиваются. Ее версия для приложений включена в Microsoft Excel, Microsoft Access, многие Windows-приложения используют этот язык. Подмножество языка в Visual Basic Scripting Edition (VBScript) используется для написания скрипов (сценариев). Если необходимо разработать утилиту для рабочей группы программистов, или большую систему для предприятия, или даже распределенное приложение, соединяющее через Internet весь земной шар, ( Visual Basic предоставит все необходимые средства для достижения этих целей.
Средства доступа к данным для создания базы данных, приложения предварительной обработки данных и расширяемые компоненты обслуживающих узлов (серверов) для большинства форматов баз, включая Microsoft SQL Server и другие базы предметного уровня.
Технология ActiveX для использования функций, предоставляемых другими приложениями, например, текстовым процессором Word, системой обработки электронных таблиц Excel и другими Windows-приложениями.
Поддержка Internet для легкого доступа к документам и приложениям по сетям Internet или intranet из разработанного пользователем приложения.
10.2. Основы Visual Basic
Для понимания процесса разработки приложений необходимо знать ключевые концепции, на которых базируется Visual Basic.
Среда Windows: окна, события, сообщения
Окно. Прямоугольная область со своими границами, например, окно Проводника в Windows 95, окно Документа в текстовом редакторе или диалоговое окно. Существует большое число типов окон. Так, кнопка управления является окном. Значки, текстовые поля, переключатели и меню ( все они окна. ОС Windows управляет всем этим множеством окон, назначая каждому из них уникальный идентификационный номер. Система постоянно следит за каждым окном, отмечает его активность и регистрирует происходящие в нем события.
События. Происходят в результате действий пользователя, например, щелчка кнопкой мыши или нажатия клавиши клавиатуры, в результате программного управления или даже как результат действий другого окна. Каждое событие является причиной посылки некоторого сообщения операционной системе. Система обрабатывает это сообщение и передает его другим окнам. Каждое окно затем может предпринять соответствующие действия, основанные на его собственных инструкциях относительно этого конкретного сообщения, например, снова нарисовать себя на экране после того, как оно перестало быть прикрытым другим окном. Код приложения также может инициировать события во время выполнения. Можно, например, программно изменить текст в текстовом поле, путем инициирования события Change (Изменить) для этого поля. Если предполагалось, что это событие могло быть инициировано только взаимодействием с пользователем, можно получить неожиданный результат. Таких проблем не возникает при использовании традиционной процедурной модели.
Степень сложности управления всеми возможными комбинациями взаимодействия окон, событий и сообщений чрезвычайно высока. Однако Visual Basic освобождает программиста от проблем, связанных с обработкой всех сообщений нижнего уровня. Для удобства пользователя одни сообщения автоматически обрабатываются Visual Basic, другие распознаются и обрабатываются процедурами обработки событий. Это позволяет быстро создавать мощные приложения, не обращая внимания на ненужные детали.
Интерактивная разработка
Процесс разработки традиционных приложений можно разбить на три отдельных этапа: написание, компилирование (перевод программы на язык команд компьютера) и тестирование кода. В отличие от традиционных языков в Visual Basic применяется интерактивный подход (диалог между компьютером и человеком) к разработке, стирающий различия между тремя упомянутыми этапами.
При работе с большинством языков ошибка, допущенная при написании кода, обнаруживается компилятором на этапе трансляции приложения, т.е. после написания. Ошибка отыскивается, исправляется и снова выполняется компиляция. Этот цикл повторяется для каждой обнаруженной ошибки. Система Visual Basic интерпретирует (преобразует не всю, а только отдельные предложения программы в набор команд) набираемый пользователем код, и отображает на экране информацию о синтаксических и орфографических ошибках. Это похоже на ситуацию, когда эксперт стоит за спиной программиста, смотрит на вводимый им код и моментально фиксирует ошибки. Кроме этого Visual Basic частично компилирует код по мере его ввода. Если компилятор находит ошибку, он высвечивает ее в коде самого приложения. Ее можно исправить и продолжить компиляцию, не начиная процесс с самого начала.
Вследствие интерактивной природы Visual Basic, приложение выполняется, как только разработано. Таким способом можно протестировать результаты выполнения кода достаточно быстро, так как разработчик большую часть времени работает, а не ожидает окончания компиляции.
Интегрированная среда разработки
Рабочую среду Visual Basic называют интегрированной средой разработки, сокращенно IDE, так как она совмещает в себе разнообразные функции: проектирование, редактирование, компиляцию и отладку приложения. В традиционных инструментальных средах каждая из перечисленных функций работала бы как отдельная программа со своим собственным интерфейсом.
Запуск Visual Basic IDE. Система Visual Basic в среде ОС Windows может быть запущена одним из нескольких способов, например, при помощи кнопки Пуск панели задач. Для запуска необходимо выполнить операции: 1) нажать кнопку Пуск Панели задач, 2) выбрать пункт меню Программы, 3) затем ( Системы программирования, 4) далее ( Visual Basic 6.0. В результате на экране появляется набор окон интегрированной среды разработки (IDE), которые рассмотрим.
Строка меню. Содержит команды, используемые при работе с Visual Basic. Кроме стандартных меню File, Edit, View, Window и Help, здесь расположены меню, обеспечивающие доступ к функциям программирования, например, Project, Format или Debug.
Контекстное меню. Содержит команды для часто выполняемых действий. Чтобы открыть контекстное меню, необходимо щелкнуть правой кнопкой на объекте, с которым в данный момент происходит работа. Список доступных команд из контекстного меню зависит от того, на какой области интерфейса среды разработки был выполнен щелчок. Например, контекстное меню, отображаемое в результате щелчка на Панели элементов управления, позволяет отобразить диалоговое окно Components (Компоненты). В этом окне функция Hide означает, убрать Панель элементов управления, Dock ( прикрепить или Undock ( открепить ее, или tab ( добавить к окну вкладку. Контекстное меню исчезает после выбора одного из его пунктов. Выбор пункта в меню производится левой кнопкой мыши или в результате щелчка левой кнопкой вне меню.
Панели инструментов. Предоставляют быстрый доступ к наиболее часто используемым командам среды программирования. Щелчок (если кнопка не указывается, то всегда подразумевается левая кнопка) по кнопке панели инструментов (Toolbar) вызывает выполнение действия, которое приписано этой кнопке. По умолчанию при запуске Visual Basic отображается только одна Стандартная панель инструментов (Standard Toolbar). Подключение и отключение дополнительных панелей инструментов для редактирования, разработки форм и отладки производится командой Toolbars (Панели инструментов) из меню View (Вид) или путем вызова контекстного меню (рисунок справа) щелчком левой кнопкой мыши по любой из имеющихся на экране панели инструментов. Подключенные панели отмечаются в меню флажками. Установка или удаление флажков производится левой кнопкой мыши. Панели инструментов можно зафиксировать (прикрепить) ниже панели меню или сделать перемещаемыми (Float), выбрав вертикальную полосу на левом краю и перетащив ее с панели меню.
Панель элементов управления (Toolbox). Обеспечивает проектировщика набором элементов управления, необходимых во время разработки для размещения элементов управления на форме. Иногда одного набора элементов управления не хватает. Тогда используется возможность создания множества различных наборов. Сначала на панели Toolbox находится один набор с названием General (основной) Для добавления дополнительных наборов используется пункт Add Tab контекстного меню этой панели. Разработчик указывает имя (произвольное) нового набора и с помощью пункта Components контекстного меню заполняет ее нужными элементами управления. На панели появляется столько надписей с названиями наборов, сколько их было создано. Любой из наборов, кроме General, с помощью пункта Delete Tab контекстного меню в любой момент можно удалить.
Окно Проекта. Предоставляет список форм и модулей текущего проекта. Проект ( это набор файлов, используемых для построения приложения.
Окно Свойств (Properties). Перечисляет установленные свойства для формы или элемента управления. Свойство (Property) ( это характеристика объекта, например, цвет, название, размер.
Обзор объектов (Object Browser). Вызывается с помощью соответствующей кнопки на панели управления. Средство Object Browser перечисляет доступные для данного проекта объекты и предоставляет быстрый способ навигации по коду. Object Browser используется для обследования объектов в Visual Basic и других приложениях, определяет, какие методы и свойства доступны для этих объектов и вставляет код процедур в приложение.
Окно Формы (Дизайнер). Служит в качестве окна, которое можно настроить (customize) при разработке интерфейса приложения. Для придания форме желаемого вида, программист располагает на форме или добавляет к ней элементы управления, графику и картинки. Каждая форма приложения имеет собственное окно дизайнера форм.
Окно Редактора кода. Служит для редактирования программного кода приложения. Для каждой формы или модуля кода приложения создается отдельное окно редактора кода.
Окно Компоновки форм. Позволяет задать расположение формы приложения на экране с помощью маленького графического изображения экрана, находящегося в правом нижнем углу IDE.
Окна Immediate, Locals, Watch. Предусмотрены для использования в процессе отладки приложения. Они доступны, только если приложение выполняется из IDE.
Возможности интерфейса Visual Basic можно расширить с помощью дополнительных модулей (add-ins). Эти модули, поставляются фирмой Microsoft и другими поставщиками и предоставляют, например, возможности управления исходным кодом, что позволяет поддерживать проекты, разрабатываемые группой программистов.
10.3. Формы и элементы управления
Первым шагом при разработке приложения на Visual Basic является создание интерфейса, видимой части приложения, с которым взаимодействует пользователь. Формы и элементы управления являются строительными блоками при создании интерфейса. Именно с этими объектами приходится работать при построении приложений.
Формы - это объекты, которые обладают свойствами, определяющими их внешний вид, методами, определяющими их поведение, и событиями, которые определяют их взаимодействие с пользователем. В результате установки свойств формы и разработки кода Visual Basic для отклика формы на события создается объект, удовлетворяющий требованиям определенного приложения.
Элементы управления - это объекты, содержащиеся внутри объектов-форм. Каждый тип элемента управления имеет свой собственный набор свойств, методов и событий, что делает его пригодным для определенной цели. Некоторые элементы управления, используемые в приложениях, лучше всего подходят для ввода или отображения текста. Другие элементы управления обеспечивают доступ к другим приложениям и данным процессов таким образом, как будто бы удаленное приложение является частью самого приложения.
Мы познакомимся с основными понятиями, необходимыми для работы с формами и элементами управления и связанными с ними свойствами, методами и событиями. Рассмотрим большое количество стандартных элементов управления, а также специфические для форм меню и окна диалога.
Разработка и установка свойств формы
Формы являются основными строительными блоками приложения Visual Basic. Формы имеют свои свойства, события и методы, которые позволяют управлять их внешним видом и поведением. Первым шагом в ее разработке является установка значений свойств. Свойства формы можно установить во время разработки в окне Properties (Свойства) или во время выполнения (run time) приложения, написав соответствующий код.
Многие из свойств формы воздействуют на ее внешний вид. Свойство Caption (Название) определяет текст заголовка окна (title bar) формы. Свойство Icon (Значок) устанавливает отображаемый при сворачивании формы значок. Свойства MaxButton и MinButton определяют, можно ли форму развернуть или свернуть. Изменяя установку свойства BorderStyle, можно управлять размерами формы.
Свойства Height (Высота) и Width (Ширина) определяют начальные размеры формы. Свойства Left (Левый) и Top (Верхний) определяют местоположение формы по отношению к левому верхнему углу экрана монитора. Свойство WindowState (Состояние окна) устанавливается таким образом, чтобы первое появление формы на экране происходило в свернутом, развернутом или нормальном виде.
Свойство Name (Имя) устанавливает имя, по которому можно обращаться к форме из кода. По умолчанию, когда форма впервые добавляется к проекту, ее имя может быть одним из последовательности имен Form1, Form2 и т. д.
События и методы формы
Формы могут выполнять методы и реагировать (откликаться) на события. При каждом изменении ее размера в результате действий пользователя или программным способом инициируется событие Resize (Изменить размер). Это позволяет изменять размеры элементов управления на форме или перемещать их, когда изменены размеры самой формы. Событие Activate (Активизировать) происходит всегда, когда форма становится активной, а событие Deactivate (Деактивировать) ( когда активной становится другая форма приложения. Эти события удобны для организации поведения формы при ее инициировании и завершении работы с ней. Например, можно написать код, который в случае события Activate выделит текст в каком-нибудь тeкcтoвoм окне, а в случае события Deactivate сохранит изменения в файле или базе данных. Чтобы сделать форму видимой, используется метод Show (Показать): Form2.Show. Вызов метода Show имеет тот же эффект, что и установка значения свойства Visible (Видимый) формы в True (Истина). Многие из методов формы работают с текстом или графикой. Методы Print (Печатать), Line (Линия), Circle (Окружность) и Refresh (Обновить) используются для печати или рисования непосредственно на поверхности формы.
Кнопки управления как основа выполнения действий
В качестве кнопки можно использовать элемент управления Command Button (Кнопка управления), или разработать собственную "кнопку", используя элемент управления Image (Изображение), содержащий графику. Когда пользователь нажимает кнопку, то она выглядит, как будто ее вдавливают, а потом отпускают. При щелчке на кнопке вызывается событие Click (Щелчок). Для выполнения определенных действий при щелчке на кнопке в процедуру обработки события Click помещается соответствующий код. Нажать кнопку можно, используя мышь, либо переместив фокус на нее посредством клавиши Tab, а затем используя клавиши Spacebar (пробел) или Enter (ввод), либо нажав клавишу доступа (Alt+<подчеркнутая буква в названии клавиши>) к данной кнопке, либо программным путем установив значение свойства Value (Значение) кнопки равным True (Истина). Если кнопка является кнопкой управления по умолчанию достаточно нажать клавишу Enter. Если кнопка no умолчанию является кнопкой отказа (Cancel Button), то ее выбор осуществляется по клавише Esc. Все эти действия вызывают процедуру обработки события Click.
Элементы управления для отображения и ввода текста
Элементы управления Label (Метка) и TextBox (Текстовое поле) применяются для отображения или ввода текста на форме.
Метка. Отображает текст, который пользователь не может изменять. Метки можно использовать для идентификации элементов управления, например, текстовых полей и полос прокрутки, не имеющих собственного свойства Caption (Надпись). Текст задается свойством Caption элемента. Оно может быть установлено во время разработки в окне Properties или во время выполнения оператором присваивания в программном коде. По умолчанию надпись - единственная видимая часть элемента Label. Однако если значение свойства BorderStyle установлено равным 1, то метка появляется вместе с границей, что придает ей вид, похожий на вид текстового поля. Внешний вид метки изменяется установкой свойств BackColor (Цвет Фона), BackStyle (Стиль Фона), ForeColor (Цвет Букв) и Font (Шрифт). Для задания длинных надписей, или надписей с меняющейся во время выполнения длиной используются свойства AutoSize (Авторазмер) и WordWrap (Перенос Слов), которые подгоняют их размер под переменную длину надписи. Свойство AutoSize определяет, следует ли автоматически изменять размер элемента управления, чтобы он соответствовал выводимым данным. Если значение этого свойства равно True, то горизонтальный размер метки увеличивается, чтобы на ней поместилась надпись. Свойство WordWrap увеличивает высоту метки, при этом ее ширина не меняется.
Текстовые поля. Гибкие элементами управления. Используются для ввода пользователем данных, и для отображения текста. Не рекомендуется использовать для отображения не изменяемого текста, если только значение свойства Locked (Заблокирован) не установлено в True. Отображение в поле управляется свойством Text (Текст). Оно устанавливается во время разработки в окне Properties, во время выполнения из программного кода или на основе данных, введенных пользователем. Текущее содержимое поля можно получить во время выполнения, считывая значение свойства Text.
Многострочные текстовые окна и перенос слов. По умолчанию в текстовом поле отображается одна строка текста, полосы прокрутки не отображаются. Если размер текста превышает размер доступного пространства, будет видна только часть текста. Вид и поведение поля можно изменить, посредством свойств Multi-Line и ScroliBars, которые доступны только во время разработки. Установка Multi-Line в True позволяет полю принимать и отображать много строк текста во время выполнения. Оно само управляет переходом на новую строку, если текст не помещается. По умолчанию значение свойства ScroliBars равно None (Нет). Автоматический переход на новую строку избавляет пользователя от необходимости вводить в конце строк символ разрыва строки. Если строка текста длиннее строки поля, то оно переносит вывод строки на следующую строку. Символ разрыва строки нельзя вводить в окне Properties во время разработки. В процедуре разрыв строки моделируется вводом символов возврата каретки (ВК) и перевода строки (ПС) с кодами ANSI 13 и 10. Можно также использовать константу VbCrLf для ввода символов ВК и ПС. Например, следующая процедура обработки события вводит две строки текста в поле Text1 при загрузке формы.
Sub Form_Load (}
Text1.Text = "Here are two lines" & vbCrLf & "in a text box"
End Sub
Работа с текстом в текстовом поле. Свойства SelStart, SelLength и SelText управляют точкой ввода и поведением выделенного фрагмента (Selection Behavior) в текстовом поле. Они доступны только во время выполнения. Когда поле впервые получает фокус, то по умолчанию точка ввода (положение курсора) располагается слева от текста. Пользователь может его изменить с клавиатуры или с помощью мыши. Если поле теряет, а затем вновь приобретает фокус, точка ввода будет находиться там, где пользователь установил ее в последний раз. Свойства SelStart и SelLength модифицируют поведение поля, приспосабливая его к вводу новых символов после уже существующего текста, либо к его полному замещению. Значением свойства SelStart является число, которое указывает место вставки в строке текста, причем 0 соответствует крайней левой позиции. Если значением свойства SelStart является число, равное или больше, чем число символов в текстовом окне, точка ввода находится сразу за последним символом. Число, равное значению свойства SelLength, задает ширину точки ввода. Если это число больше 0, то равное ему количество символов, начиная от текущей точки ввода, выбирается и выделяется. Если пользователь начинает ввод при выделенном блоке текста, то последний будет замещен вводимым текстом. При необходимости можно заменить выделенный текст новым с помощью команды Paste (Вставить) меню Edit (Правка). Значением свойства SelText является строка текста, которую можно присвоить во время выполнения и которая заменит выделенный текст. Если такового нет, то в текущую точку ввода помещается значение свойства SelText.
10.4. Элементы управления пользователя
Пользователю предоставляются разнообразные возможности выбора, начиная от простейшего (флажки, переключатели), до сложного из списка (список, комбинированное окно).
Флажки и переключатели
Флажки. Показывают, включены ли определенные условия. Используются для организации выбора типа "правда/ложь" или "да/нет". Флажки работают независимо друг от друга, поэтому пользователь может установить любое их число.
Переключатели. Предоставляют выбор из двух и более возможностей. В отличие от флажков, они всегда работают как часть группы – выбор одного сбрасывает все другие переключатели группы. Объединение переключателей в группу означает, что пользователь может выбрать одну и только одну возможность из заданного их набора.
Создание групп переключателей. Все переключатели, размещенные непосредственно на форме, составляют одну группу. Если необходимо создать дополнительные группы переключателей, то их следует поместить внутрь рамок (Frame) или графических окон (Picture). Все переключатели внутри этих рамок или графических окон составляют отдельные группы. При создании отдельной группы переключателей сначала создается рамка или графическое окно, а затем поверх них – переключатели. При перемещении рамки вместе с ней будут перемещаться и все элементы внутри нее.
Контейнеры для элементов управления. Элементы управления являются независимыми объектами, однако между ними и формами существуют отношения подчиненности. Для понимания идеи контейнеров необходимо понимать, что все элементы управления являются подчиненными по отношению к форме, на которой они нарисованы. Фактически большинство элементов поддерживает свойство parent (Родитель) в режиме "только чтение", т. е. значением этого свойства является форма, на которой расположен элемент, и его изменить невозможно. Положение элемента ограничено родительской формой, по отношению к которой он является подчиненным. Свойства Left и Top элемента связаны с родительской формой, и поэтому его нельзя переместить за границы формы. Перемещение контейнера также приводит к перемещению элементов управления, но не изменяет значений их свойств Left и Top.
Комбинированные окна и списки
Списки и комбинированные окна. Предоставляют пользователю возможные варианты выбора, по умолчанию отображаемые вертикальным списком в одну колонку, хотя возможно отображение и несколькими колонками. Если число элементов превышает возможности отображения в комбинированном окне или списке, автоматически появляется полоса прокрутки. Пользователь в этом случае может просматривать список элементов, прокручивая его вверх и вниз или влево и вправо.
Комбинированное окно. Совмещает возможности списка и текстового поля. В этом элементе управления пользователь может производить выбор либо вводом текста в поле ввода комбинированного списка, либо выбором элемента из его списка.
В отличие от других элементов управления, которые содержат одно значение, например, значения свойства Caption метки или Text текстового поля, списки и комбинированные окна содержат набор значений. Для них существуют встроенные методы добавления, удаления и получения значений из этого набора во время выполнения. Например, программный код для добавления нескольких элементов в список с именем List1: List1.AddItem "Paris": List1.AddItem "New York": Listl.AddITem "San Francisco"
Полосы прокрутки. Используются в текстовых полях или окнах, но иногда их применяют в качестве устройств ввода. Полосы прокрутки показывают текущую позицию на масштабной линейке, поэтому их можно использовать самостоятельно для управления вводом в программу, например, регулировать цветовую палитру в картинке или уровень громкости. Элементы HScrollBar (Горизонтальная полоса прокрутки) и VScrollBar (Вертикальная полоса прокрутки) функционируют независимо от других элементов и имеют собственные наборы событий, свойств и методов. Современная тенденция построения интерфейса Windows предполагает использовать полосы-регуляторы (Slider Controls) вместо полос прокрутки (Scroll Bars).
Графические элементы управления
К графическим элементам управления относятся четыре объекта: Picture (Графическое окно), Image (Изображение), Shape (Контур) и Line (Линия). Объекты Image, Shape и Line называют "облегченными" графическими элементами управления. Им требуется меньше системных ресурсов и они отображают графические образы быстрее, чем элемент Picture.
Графическое окно. Объект Picture Box (Графическое окно) используется для отображения картинок. Свойство Picture (Картинка) определяет, какая картинка будет отображена. Значением этого свойства является имя файла, содержащего картинку. Объект Form также имеют свойство Picture, которое устанавливается для отображения картинки в виде фона формы. Для отображения или замены картинки во время выполнения устанавливается значение свойства Picture при помощи функции LoadPicture. Ей передается только имя файла картинки, и далее она управляет загрузкой и отображением картинки: PicMain.Picture = LoadPicture("VAHGOSH.BMP"). Объект Picture имеет свойство AutoSize, которое, если его значение равно True, автоматически изменяет размеры окна вывода картинки, чтобы оно соответствовало размерам выводимой картинки. Размеры окна вывода картинки изменяются независимо от других элементов на форме. В результате картинка может их закрыть.
Графическое окно в качестве контейнера. Может выполнять функции контейнера для других элементов управления. Помещенные элементы будут перемещаться вместе с окном, а их свойства Top и Left будут подчинены ему, а не форме. Графическое окно в качестве контейнера используют для того, чтобы создать панель инструментов или строку состояния. Туда можно поместить элементы Image, чтобы они выступали в качестве кнопок, или добавить метки для отображения сообщений о состоянии. Устанавливая значение свойства Align (Выровнять) равным Top (Верх), Bottom (Низ), Left (Лево) или Right (Право) можно "прикрепить" графическое окно к соответствующему краю формы.
Другие применения элемента управления Picture. В графическом окне можно рисовать, чертить или печатать. Этот элемент можно использовать для отображения текста, графики и даже анимации. Объект Picture имеет несколько методов. Метод Print (Печать) выводит текст в окно, как на принтер. Свойства установки шрифтов управляют параметрами выводимого текста. Метод Els используется для удаления выведенного текста. Методы Circle (Окружность), Line (Линия), Point (Точка) и Pset (Набор точек) используются для вычерчивания графических элементов в окне. Свойства DrawHidth, FillColor, и FillStyle изменяют внешний вид графических элементов. Анимация создается методом PaintPicture, который перемещает изображения в окне и чередует их быструю смену.
Элемент управления Image. Объект Image похож на Picture, но используется только для отображения картинок. Он не может выступать в качестве контейнера для других элементов и не поддерживает некоторые методы графического окна. Картинки загружаются так же, как и в Picture посредством функции LoadPicture. Объект Image не имеет свойства AutoSize, он обладает свойством Stretch (Растягивание). Присвоение свойству значения False приводит к тому, что размеры элемента изменяются в соответствии с размерами картинки. Если свойство равно True, то размеры картинки изменяются до размеров элемента Image, что может привести к искажению картинки. Объект Image распознает событие Click, что полезно при создании кнопок с картинками вместо надписей. Объединение нескольких элементов Image в группу позволяет создавать панели инструментов приложения. В отличие от кнопок, элементы Image не вдавливаются, если на них выполняется щелчок.
Элементы управления Shape и Line. Объекты Shape и Line полезны при вычерчивании графики на поверхности формы. Эти элементы не поддерживают никаких событий, они существуют исключительно для декоративных целей. Для объекта Shape предусмотрено несколько свойств, которые управляют его внешним видом. Задавая значения свойству Shape этого элемента, можно отображать его в виде прямоугольника, квадрата, овала, окружности, прямоугольника или квадрата со скругленными углами. Свойства BorderColor и FillColor используются для изменения цвета, свойства BorderWidth, FillStyle и DrawMode управляют параметрами вычерчивания графического образа. Объект Line подобен объекту Shape, но применяется только для вычерчивания прямых линий.
Другие стандартные элементы управления
Элементы управления доступом к данным. Система Visual Basic содержит элементы управления доступом к данным наиболее популярных баз, включая Microsoft Access и SQL Server.
Элемент ADOData используется для подсоединения к базе данных. Его можно считать неким каналом между базой и другими элементами на форме. Его свойства, методы и события позволяют из приложения просматривать внешние данные и управлять ими. Элемент DataList похож на список. Когда он применяется совместно с элементом ADOData, то он автоматически заполняется списком данных из поля внешней базы данных. Элемент DataCombo подобен комбинации элемента DataList и текстового поля. Выбранный в его поле текст, можно редактировать, причем одновременно происходят изменения в базе данных. Элемент DataGrid отображает данные в таблице. Совместно с элементом ADOData он отображает полностью редактируемые данные из множественных полей базы данных. Элемент Microsoft Hierarchical FlexGrid является единственным элементом управления для представления различных видов отображения данных. Его можно рассматривать как комбинацию табличного элемента управления (grid control) и элемента управления деревом (tree control) или элемента управления очертанием (outline control). Во время выполнения пользователь может переставлять столбцы и строки, чтобы получить различные виды отображения данных.
Файловые элементы управления. Имеются три элемента, позволяющие приложению управлять файлами. Обычно они используются совместно для просмотра дисководов, каталогов и файлов. Они имеют специальные свойства и события, связывающие их вместе.
Элемент DriveListBox выглядит как комбинированное окно. Он предоставляет раскрывающийся список дисководов, из которого производится выбор. Элемент DirListBox подобен списку, но со встроенной возможностью отображения списка каталогов на выбранном дисководе. Элемент FileListBox также выглядит, как список с именами файлов в выбранном каталоге. Элемент управления общим диалогом (common dialog control) облегчает метод работы с файловой системой.
Другие элементы управления. Элемент Timer (Таймер) используется для создания события через повторяющийся интервал времени без взаимодействия с пользователем. Элемент OLE Container (Контейнер OLE) обеспечивает добавление в приложение возможностей связывания и внедрения. Посредством него обеспечивается доступ к выполняемым функциям любого приложения, поддерживающего OLE-технологию, например Excel, Word и др. Элемент Common Dialog (Общий диалог) добавляет в приложение встроенные диалоговые окна для выбора файлов, цветов, шрифтов, функций печати.
10.5. Фокус. Последовательность переходов. Меню
Фокус
Объект, имеющий фокус, может получать от пользователя с помощью мыши и клавиатуры информацию. В системе Windows одновременно могут выполняться несколько приложений, но только у приложения, имеющего фокус, будет активный заголовок окна, который выделяется повышенной яркостью. Только это окно может взаимодействовать с пользователем. На форме приложения с несколькими полями ввода только поле, имеющее фокус, будет отображать вводимый с клавиатуры текст. Когда объект получает или теряет фокус, происходят соответственно события GetFocus и LostFocus. Формы и большинство элементов управления поддерживают эти события. Объекту можно передать фокус с помощью мыши и клавиши доступа во время выполнения, а также из программного кода с помощью метода Set Focus. Объект получает фокус, если его свойства Enabled (Разрешено) и Visible (Видимый) установлены в True. Свойство Enabled позволяет объекту реагировать на инициированные пользователем события, например, ввод с клавиатуры и нажатие кнопок мыши. Свойство Visible определяет, виден ли объект на экране.
Элементы управления имеют событие Validate (Проверка достоверности). Оно происходит перед тем, как элемент теряет фокус. Однако это событие возникает, только если свойство CausesValidation элемента перед получением фокуса имело значение True. Событие Validate происходит перед потерей фокуса, поэтому во многих случаях оно более подходит для проверки достоверности данных, чем событие LostFocus. Некоторые элементы не могут получать фокус. К ним относятся: Frame (Рамка), Image (Изображение), Label (Метка), Line (Линия), Shape (Контур), Timer (Таймер).
Установка последовательности перехода
Последовательность перехода (Tab Order) - это последовательность перехода от элемента управления к элементу по клавише Tab. У каждой формы своя последовательность перехода. Обычно она соответствует последовательности создания элементов.
Пусть созданы два поля ввода и кнопка. При запуске приложения первое созданное поле имеет фокус. Нажатие клавиши Tab перемещает фокус на второе созданное поле, а последующее нажатие на кнопку. Для изменения последовательности перехода необходимо установить свойство TabIndex элемента, которое определяет его позицию в последовательности переходов. По умолчанию его значение для элемента, созданного на форме первым, равно 0, у элемента, созданного вторым - 1 и т. д. При изменении позиции элемента в последовательности переходов автоматически перенумеровываются позиции других элементов, отражая вставку или удаление элемента. Элементы управления, которые не могут получить фокус, при нажатии клавиши пропускаются. Для удаления элемента из последовательности перехода следует установить значение его свойства TabStop равным False или 0. При этом элемент сохраняет свою позицию в последовательности перехода, но при переходе от элемента к элементу по клавише Tab он пропускается.
Основы меню
Меню – это способ объединения команд в группу для эффективной организации доступа к ним пользователя. Обычно Строка меню располагается сразу под заголовком окна на форме и содержит одно или более меню. При выборе меню, например, File, раскрывается список пунктов этого меню, если он существует. Пункты могут быть командами, например, New и Exit, разделителями и подменю. Внешний вид пунктов меню определяется в элементе управления Menu (Меню) с помощью Редактора меню (Menu Editor). Для удобства работы с приложением пункты меню следует группировать в соответствии с их функциональным назначением. Например, команды работы с файлами New (Создать), Open (Открыть) и Save As (Сохранить как) находятся в меню File (Файл). Некоторые команды меню выполняются немедленно, например, команда Exit (Выход) меню File закрывает приложение. Другие команды отображают диалоговые окна - окна, в которых пользователь задает необходимую для выполнения команды информацию. Названия таких команд должны заканчиваться многоточием '...'. Например, при выборе команды Save As... меню File появляется диалоговое окно Save File As (Сохранить файл как). Элемент Menu имеет свои свойства, которые используются для задания его внешнего вида и поведения. К ним относятся свойства Caption (Надпись), Enabled (Разрешено), Visible (Видимый), Checked (Установлено) и многие другие, которые устанавливаются во время разработки, или выполнения. Меню имеют только одно событие Click (Щелкнуть), вызываемое при их выборе посредством мыши или клавиатуры.
Контекстные меню
Контекстное меню – это меню, которое отображается в любом месте формы и не привязано к строке меню. Оно вызывается щелчком правой кнопки мыши, а набор его команд зависит от местоположения курсора мыши в момент щелчка. Такое меню следует использовать для предоставления пользователю эффективного метода доступа к часто используемым контекстно-зависимым командам. Например, щелкнув правой кнопкой мыши на текстовом поле, можно отобразить контекстное меню, с командами по работе с этим полем. Любое меню, содержащее даже одну команду, может быть отображено во время выполнения как контекстное меню. Для этого применяется метод PopupMenu.
Редактор меню
С помощью Редактора меню (Menu Editor) можно добавлять команды в существующие меню, заменять их команды собственными, создавать новые меню и строки меню, изменять и удалять меню существующей ее строки. Основное преимущество Menu Editor заключается в удобстве работы. Меню разрабатываются интерактивным способом, требующим минимального программирования. Редактор вызывается командой Menu Editor меню Tools. В результате открывается окно Menu Editor.
Хотя большинство свойств элемента управления Menu можно установить в Menu Editor, предусмотрена возможность доступа ко всем свойствам меню и в окне Properties. Рекомендуется создавать меню с помощью Menu Editor, но для быстрого их изменения можно использовать и окно Properties.
Подсказки пользователю с помощью диалога
В Windows-приложениях окна диалога или диалоговые окна используются для подсказки пользователю о вводе данных, необходимых для работы приложения, или отображения некоторой информации. Окна диалога (специальный вид формы) создаются тремя способами: 1) из программного кода с помощью функций МsgВох или InputBox, 2) с использованием стандартных форм или видоизменением существующего диалогового окна, 3) с помощью элемента управления общим диалогом (Common Dialog Control). Например, создадим окно с помощью функции МsgBох. Для этого в программном коде необходимо поместить ее вызов (справа). В функцию MsgBox информация передается через аргументы: 1) текст сообщения, 2) числовая константа, определяющая стиль окна диалога, 3) заголовок. Для создания окон диалога можно использовать разнообразные стили с различными комбинациями кнопок и значков.
Так как большинство окон диалога взаимодействуют с пользователем, то обычно они отображаются как модальные окна диалога. Модальное окно должно быть закрыто (спрятано, Hidden) или выгружено (unloaded) прежде, чем пользователь продолжит работу с приложением. Например, окно диалога является модальным, если в нем требуется нажать кнопки ОК или Cancel (Отмена) прежде, чем можно будет переключиться на другую форму или окно диалога. Безрежимные окна диалога поддерживают переключение фокуса между окном диалога и другой формой без необходимости закрытия самого окна. Безрежимные окна редки; обычно приложение отображает диалоговое окно, поскольку для продолжения его работы требуется дополнительная информация. Окно Find (Найти) меню Edit (Правка) являются примером модального окна. Этот тип окна следует использовать для отображения наиболее часто используемых команд или информации.



Тема 11
Управление проектами
Частью современной интегрированной среды является система управления проектами. При создании приложения программист работает с проектами. Проект (Project) - это набор файлов, используемых для построения приложения. При построении приложения обычно создаются новые формы, используются или модифицируются старые формы из предыдущих проектов. Это же справедливо и для других модулей или файлов, которые могут быть включены в проект. Элементы управления ActiveX и объекты из других приложений могут также использоваться совместно в нескольких проектах. Когда все компоненты проекта собраны и написан программный код приложения, проект транслируется и создается выполняемый файл.
11.1. Работа с проектом и его структура
Проект состоит из следующих файлов.
Файл проекта. Хранятся связи между всеми компонентами проекта (расширение vbp).
Файлы форм (расширение frm). Один файл для каждой формы.
Файлы двоичных данных (файл на форму). Содержит данные для свойств элементов управления на форме (расширение frx). Эти файлы нельзя редактировать, они автоматически создаются для форм, содержащих свойства Picture (Картинка) или Icon (Значок);
Необязательные файлы для модулей классов. Файл на модуль. Расширение cls.
Необязательные файлы для стандартного модуля. Файл на модуль Расширение bas.
Необязательные файлы, содержащие элементы управления ActiveX, расширение ocx.
Необязательный файл ресурсов. Расширение res.
Файл проекта является списком всех файлов и объектов, связанных с проектом, а также содержит информацию о параметрах конфигурации проекта, установленных пользователем. Эта информация корректируется при сохранении проекта. Все файлы и объекты могут использоваться и другими проектами. После создания файлов проекта может создаваться выполняемый exe-файл. Для этого в меню File (Файл) достаточно выбрать команду Make (Создать) <имя проекта>.exe.
Создание, добавление или удаление редактируемых файлов проекта отражается в окне Project Explorer (Окно проводника проекта), в котором находится текущий список всех основных файлов проекта. Некоторые файлы, например файлы двоичных данных форм с расширением frx, в этом окне не высвечиваются. Файлы проекта могут располагаться в разных папках. При каждом сохранении проекта информация о нем корректируется в файле проекта (расширение vbp). Этот файл содержит тот же список файлов, что и окно Project, а также ссылки на элементы управления ActiveX и вставляемые объекты. Открытие файла проекта производится двойным щелчком по его значку в окне команды Open Project (Открыть проект) меню File.
Структура проекта
Модули форм содержат текстовые описания формы и ее элементы управления, включая установленные значения их свойств. В них также содержаться объявления используемых в форме констант, переменных, внешних процедур, процедур обработки событий и процедур общего назначения.
Модули классов похожи на модули форм за исключением того, что у них нет видимого интерфейса пользователя. Они используются для создания собственных объектов, включая программный код для методов и свойств.
Стандартные модули содержат объявления открытых или используемых в модуле типов, констант, переменных, внешних процедур и открытых процедур.
Файлы ресурсов содержат растры картинок, текстовые строки и данные, изменение которых не требует редактирования кода. Если планируется локализовать приложение (приспособить к эксплуатации в определенной стране), можно хранить все текстовые строки и растры в файле ресурсов, а затем локализовать только этот файл. Проект содержит только один файл ресурсов.
Документы ActiveX хранятся в файлах с расширением dob, похожи на формы, но отображаются браузерами, например Internet Explorer. Основное назначение – подготовка информации для передачи по сети Интернет.
Модули User Control (расширение etl) и Property Page (расширение pag) также похожи на формы, и применяются при создании элементов управления ActiveX и их страниц связанных свойств для отображения свойств времени разработки.
Команды меню File для создания, открытия и сохранения проекта.
Команда меню
Описание

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

Open Project
(Открыть проект)
Закрывает текущий проект, подсказывая сохранить измененные файлы. Открывает существующий проект, включая формы, модули и элементы управления ActiveX.

Save Project
(Сохранить проект)
Обновляет файл текущего проекта и всех его форм, стандартных модулей и модулей классов. Обновление означает, что старые варианты файлов не сохраняются.

Save Project As
(Сохранить проект как)
Создает новый файл текущего проекта с указанным именем. При этом запрашивается обновление файлов измененных модулей и форм.

Возможно совместное использование одних и тех же составляющих проект файлов в разных проектах. Заметим, что изменения, сделанные в форме или модуле в одном проекте распространяются на все проекты, совместно использующие эту форму или модуль.
11.2. Работа с несколькими проектами
В некоторых версиях VB можно одновременно открыть несколько проектов. Это полезно для построения и тестирования решений, связанных с созданными элементами управления или другими компонентами. Если загружено более одного проекта, заголовок окна Проводника проекта меняется на Project Group (Группа проектов) и в нем отображаются компоненты всех открытых проектов.
Для добавления дополнительного проекта в текущую группу проектов следует выполнить команду Add Project (Добавить проект) меню File (Файл) и выбрать существующий проект или тип нового проекта, нажав кнопку Open (Открыть). Для удаления проекта из текущей группы проектов следует выбрать проект или компонент проекта в Project Explorer и в меню File выполнить команду Remove Project (Удалить проект). Работа с файлами проекта аналогична работе с проектами. Для добавления файла в проект следует выполнить команду Add (Добавить) меню Project и выбрать существующий файл или задать тип нового файла, нажав кнопку Open (Открыть).
При добавлении файла в проект включается ссылка на существующий файл, но сама копия файла не добавляется. Таким образом, если файл изменен и сохранен, то внесенные в файл изменения затронут любой проект, куда включен этот файл. Чтобы изменения файла, произведенные в одном проекте, не влияли на другие проекты, следует выбрать файл в Project Explorer, выполнить команду Save As (Сохранить как) меню File (Файл) и сохранить файл под другим именем. Для удаления файла из проекта следует выбрать файл в Project Explorer, выполнить команду Remove (Удалить) меню Project или воспользоваться соответствующим пунктом контекстно-зависимого меню. Файл будет удален из проекта, но не с диска. Удаление файла из проекта отражается в vbp-файле проекта при его сохранении. Для сохранения файла без сохранения всего проекта следует выбрать файл в Project Explorer и выполнить команду Save (Сохранить) меню File или воспользоваться соответствующим пунктом контекстно-зависимого меню.
При написании кода в текст модулей кода можно вставлять текст из других файлов, например, для добавления списка констант или фрагментов кода. Для вставки текстового файла в код в окне Project выбирается форма или модуль, нажимается кнопка View Code (Просмотр кода) и в окне Code Editor (Редактор кода) курсор устанавливается на место вставки текста. Далее выполняется команда Insert File (Вставить файл) меню Edit (Правка) и выбирается имя текстового файла, который предполагается вставить, посредством нажатия кнопки Open (Открыть).
Особенностью проекта является его способность сохранять состав панели элементов управления. Для каждого проекта можно создать присущий ему набор элементов в Панели элементов управления. Любой элемент, который добавляется на форму проекта, должен находиться в Панели элементов управления. Основной набор стандартных элементов, который всегда находится в Панели и порядок добавления и удаления элементов, а также создания дополнительных именованных наборов элементов уже были рассмотрены ранее.
Для добавления элементов управления в инструментарий проекта следует воспользоваться командой Components (Компоненты) меню Project или таким же пунктом контекстного меню. Список элементов в окне диалога Components включает все зарегистрированные элементы управления ActiveX, вставляемые объекты и дизайнеры ActiveX. Выбор элемента, добавляемого в Панель элементов управления, производится посредством установки флажка слева от имени элемента управления (файл с расширением ocx) или вставляемого объекта и нажатия кнопки ОК для закрытия диалогового окна Components. Элементы управления с расширением ocx, следует просматривать по вкладке Controls (Элементы управления). Вставляемые объекты, например, таблица Microsoft Excel, находится на вкладке Insertable Objects (Вставляемые объекты). Выбранные элементы управления ActiveX и вставляемые объекты появятся в Панели элементов управления. Отсутствие нужного элемента управления в окне Components означает, что он не зарегистрирован. При наличии ocx-файла, содержащего этот элемент, для добавления элемента управления ActiveX в окно диалога Components следует использовать кнопку Browse (Обзор) этого окна и указать каталог, содержащий этот файл. Для удаления элементов управления из проекта следует выполнить команду Components меню Project и сбросить флажок рядом с каждым удаляемым элементом управления. Значки соответствующих элементов управления будут удалены из инструментария.
Можно использовать объекты других приложений, например, из библиотеки Excel, либо как элементы управления через Панель элементов управления, либо как программируемые объекты в программном коде. Чтобы сделать доступными в коде объекты других приложений, но не в качестве элементов управления, следует установить ссылку на библиотеку объектов этого приложения. Добавление ссылки на эту библиотеку производится по команде References (Ссылки) меню Project посредством установки флажка рядом со ссылкой, добавляемой в проект. Для добавления ссылок, не перечисленных в окне диалога References (Ссылки), следует воспользоваться кнопкой Browse (Обзор) для выбора соответствующего приложения. Выбранные ссылки добавляются в проект по кнопке ОК. Если из библиотеки, установленной для ссылок на объекты, в приложении не используется ни один объект, следует сбросить флажки ссылок на объекты этой библиотеки для минимизации времени компиляции проекта. Установление ссылок на библиотеки объектов, делает доступными эти объекты, их методы и свойства, которые можно просмотреть в окне диалога Object Browser (Просмотр объектов), открываемого командой Object Browser меню View (Вид). В программном коде можно использовать любой объект, перечисленный в диалоговом окне Object Browser.
Файл ресурсов позволяет собрать в одном месте специфические для версии приложения текст и растры. Они могут содержать объявления констант, значки, экранный текст и другой материал, который может изменяться от одной локализованной версии к другой, от одного издания к другому или в соответствии со спецификой конфигурации системы, в которой будет выполняться приложение.
11.3. Создание и запуск выполняемого файла. Компиляция
Выполняемый exe-файл создается по команде Make (Создать) <имя проекта>.exe меню File. В диалоговом окне Make Project имя файла вводится через клавиатуру или через просмотр каталогов файлов и выбор имени. Через окно Project Properties (Свойства проекта), вызываемого по кнопке Make Project, задается номер версии выполняемого файла. Для автоматического увеличения номера версии проекта по команде Auto Increment (Автоувеличение) при каждом выполнении команды Make устанавливаются номера Major (Главный), Minor (Второстепенный) и Revision (Издание).
Для задания нового имени приложения в группе Application (Приложение) используется поле ввода Title (Заголовок), а чтобы прикрепить новый значок, следует выбрать его из списка значков. Комментарии (название фирмы, товарный знак, информация об авторских правах и т. д.), относящиеся к версии приложения, вводятся через список Version Information (Информация о версии), в котором выбирается нужный раздел. Компиляция и сборка выполнимого файла производится после закрытия окна диалога Project Properties и нажатия кнопки ОК в окне диалога Make.
Условная компиляция позволяет выборочно компилировать некоторые части программы. В разные версии программы можно включить относящиеся к данной версии некоторые особенности, например, фильтр изменения отображения даты и валюты для приложения, распространяемого на нескольких иностранных языках.
11.4. Установка параметров проекта
Проект оформляется с помощью установки его параметров. Для этого используется окно диалога Project Properties, вызываемое командой Project Properties меню Project или одноименный пункт контекстного меню. Установленные параметры (см. табл.) сохраняются в файле проекта. Можно установить множество других параметров проекта, включая опции компиляции, параметры для компонентов и для организации потоков (Multithreading).
Параметр
Описание

Startup Object
Первая форма, отображаемая во время выполнения или процедура Sub Main ().

Project Name
Идентифицирует код проекта при помощи некого имени. Имя не может содержать точек, скобок, пробелов и должно начинаться с буквы. Длина имени не более 37 символов.

Help File
Имя файла Справки (Help), связанного с данным проектом.

Project Help
Context ID
Контекстный ID, задаваемый для того, чтобы вызывалась определенная тема Справки, когда пользователь нажимает кнопку ? при работе с библиотекой объектов приложения.

Project
Description
Удобное для пользователя имя проекта отображается в диалоговых окнах References (Ссылки) и Object Browser (Просмотр объектов).

11.5. Дополнения и мастера
Система VB позволяет выбирать и управлять дополнительными модулями (Add-ins), которые расширяют возможности создания проектов. Мастера (Wizards) – это дополнения, облегчающие выполнение некоторых задач, например, задачи создания формы.
Добавить или удалить дополнение в проект можно с помощью Add-In Manager (Диспетчера дополнений), который вызывается из меню Add-Ins (Дополнения). В диалоговом окне Add-In Manager перечисляются все доступные модули из группы Load Behavior (Загрузить функции), которые выбираются с помощью флажков. В зависимости от сделанного выбора подсоединятся выбранные модули или отключатся те, флажки которых сброшены.
Мастера облегчают работу, предоставляя помощь при выполнении определенной задачи. Например, Application Wizard (Мастер приложения), помогает создать структуру приложения с помощью серии вопросов и возможных ответов. Он создает формы и код для них в соответствии с ответами пользователя. После этого разработчик добавляет свой код. Некоторые издания VB предоставляют и другие мастера, включая Data Form Wizard (Мастер формы данных) для создания форм, работающих с базами данных, и ActiveX Document Wizard (Мастер документа ActiveX) для преобразования форм VB в формы Интернет. Мастера устанавливаются и удаляются с помощью Add-In Manager. Однажды установленные, они появляются в виде дополнительных пунктов меню Add-Ins (Дополнения). Для вызова некоторых мастеров в соответствующих окнах диалога также создаются значки, например, Application Wizard (Мастер приложения) можно вызвать с помощью его значка в диалоговом окне New Project (Новый проект).

Тема 12
Управляющие конструкции
12.1. Конструкции принятия решения (ветвление)
Используются три конструкции принятия решения: IfThen, IfThenElse, Select Case.
Конструкция 1
Конструкция 2

If Дата < Now Then Дата = Now,
где Now - системная дата
If anyDate < Now Then
anyDate = Now
End If

Конструкция IfThen. Применяется, когда необходимо выполнить один или группу операторов в зависимости от некоторого условия. Синтаксис конструкции позволяет задать ее в одной строке или нескольких строках программы (блоковая конструкция). Обычно условие является логической величиной, но оно может быть любым выражением с числовым значением. Значение интерпретируется как True (Истина) или False (Ложь) в соответствии со следующим правилом: нулевое значение – False (Ложь), любое ненулевое значение – True (Истина). Если условие истинно, выполняются все операторы, стоящие после ключевого слова Then. Следующие две конструкции эквивалентны. Синтаксис конструкции ifThen для одной строки не требует оператор End if. Чтобы выполнить последовательность операторов следует использовать блоковую конструкцию ifThenEnd if.
Конструкция lfThenElse. Определяет несколько блоков операторов, один из которых будет выполняться в зависимости от условия. Сначала проверяет первое условие 1. Если оно ложно, то проверяет следующее условие 2 и т. д., пока не найдется истинное условие. Для него выполняется соответствующий блок операторов, а затем управление передается инструкции, следующей за оператором End if. В данную конструкцию можно включить блок оператора Else, который выполняется, если не выполнено ни одно из условий.
Конструкция If...Then...ElseIf (ElseIf пишется слитно, а End if – раздельно) в действительности всего лишь специальный случай конструкции If...Then...Else. В данной конструкции может быть любое число блоков ElseIf, или ни одного. Блок Else можно включать независимо от присутствия или, наоборот, отсутствия блоков ElseIf. Например, приложение может выполнять разные действия в зависимости от того, на каком элементе управления из массива меню элементов выполнен щелчок. В конструкцию If... Then можно добавлять любое число блоков ElseIf. Однако при большом числе этих блоков конструкция становится громоздкой и неудобной. В этом случае, если условие содержит одно и то же проверяемое выражение, применяют другую конструкцию – Select Case.
Конструкция Select Case. Конструкция является альтернативой конструкции IfThenElse когда выполняется блок из большого набора операторов. Она предоставляет возможности, аналогичные возможности ifThenElse, но в отличие от нее делает код удобочитаемым.
Конструкция Select Case работает с единственным проверяемым выражением, которое вычисляется один раз при входе в конструкцию. Результат вычисления сравнивается со значениями, задаваемыми списками других выражений в операторах Case. Если найдено совпадение, выполняется блок операторов, непосредственно следующих за оператором case, в котором это совпадение найдено. В каждом из списков значений может быть одно или более значений. Выражения в списке отделяются друг от друга запятыми. Список можно задавать также интервалом значений в виде: <начало интервала> to <конец интервала>. Если вычисленному значению проверяемого выражения соответствуют значения из нескольких операторов Case, то выполняется блок операторов, ассоциированный с первым оператором Case из всех найденных соответствий. Блок операторов, ассоциированный с необязательным оператором Case Else, выполняется если не найдено ни одного соответствия проверяемого значения выражения и значений из всех списков операторов Case. Рассмотрим использование структуры Select Case на ранее приведенном примере. Предположим, что в меню добавлена команда Edit (Правка). Можно добавить оператор ElseIf, но лучше использовать конструкцию Select Case. Конструкция Select Case вычисляет выражение только один раз при входе в нее, а конструкция If Then Else вычисляют различные выражения для каждого оператора ElseIf. Таким образом, конструкцию If Then Else можно заменить конструкцией Select Case, только если оператор if и каждый оператор ElseIf при проверке условия выбора вычисляют одно и то же выражение.
12.2. Циклы
Применяются три типа циклов: Do...Loop, For...Next, For Each...Next.
Конструкция Do...Loop применяется для выполнения блока операторов неограниченное число раз. Существует несколько разновидностей конструкции, но каждая из них вычисляет выражение-условие, чтобы определить момент выхода из цикла. Как и в случае конструкции IfThen условие должно быть выражением, принимающим значение False (нуль) или True (не нуль). Сначала проверяет условие. Если оно ложно (False), все операторы блока операторов пропускаются. Если оно истинно (True), выполняются операторы цикла, производится возврат к оператору Do while и вновь проверяется условие. Цикл будет выполняться до тех пор, пока условие принимает значение True (Истина). Операторы тела цикла не выполняются ни разу, если при первой проверке условие не выполняется. В примере подсчитывается, сколько раз встретится заданная строка Подстрока внутри строки ДлиннаяСтрока. Для этого используется функция InStr. Цикл, выполняется пока в процессе просмотра заданной строки в ней находятся подстроки, совпадающие с заданной.
Другая разновидность конструкции DoLoop конструкция DoLoop While, сначала выполняет операторы тела цикла, а затем проверяет условие после каждого выполнения. Эта разновидность гарантирует, что операторы тела цикла выполнятся, по крайней мере, один раз. Две другие разновидности конструкции цикла аналогичны предыдущим, за исключением того, что при помощи ключевого слова Until цикл выполняется, пока условие ложно (False). 1) Цикл Do UntilLoop не выполняется вообще или выполняется, пока <условие> не примет значение Истина. 2) Цикл DoLoop Until выполняется, по крайней мере, один раз.
Конструкция For...Next. Циклы Do хорошо работают, когда не известно, сколько раз необходимо выполнить операторы цикла. Когда же число повторений заранее известно, лучше использовать цикл For...Next. В отличие от цикла Do, в цикле For используется переменная, называемая переменной или счетчиком цикла, которая увеличивается или уменьшается на заданную величину при каждом повторении цикла. Параметр переменная цикла должен быть числового типа. Параметры начальное значение, конечное значение и шаг изменения также должны быть числового типа и могут задаваться константами, переменными или выражениями со значениями одного из числовых типов. Параметр шаг изменения может быть положительным и отрицательным числом. Если он положителен, параметр начальное значение должен быть меньше или равен параметру конечное значение. Если параметр шаг изменения отрицателен, то параметр начальное значение должен быть больше или равен значению параметра конечное значение, чтобы выполнялось тело цикла. Нарушение этих соотношений приводит к невыполнению цикла. Если параметр Step не задан, то значение параметра шаг изменения по умолчанию берется равным 1. В следующем примере цикл For используется для распечатки имен всех доступных экранных шрифтов.
Конструкция For EachNext. похож на цикл ForNext, но он повторяет группу операторов для каждого элемента из набора объектов или из массива, вместо повторения операторов заданное число раз. Он особенно полезен, когда неизвестно, сколько элементов содержится в наборе или массиве. Его синтаксис справа. Например, следующая процедура открывает файл Biblio.mdb и добавляет имя каждой таблицы в список. Следует помнить следующие ограничения при использовании цикла For Each...Next.
Для наборов параметр элемент может быть только переменной типа variant, object или объектом, перечисленным в Object Browser.
Для массивов параметр элемент может быть только переменной типа Variant.
Нельзя использовать цикл For Each... Next с массивом, имеющим определенный пользователем тип, так как переменная типа variant не может содержать значение определенного пользователем типа.
12.3. Работа со структурами управления и досрочный выход из них
Вложенные структуры управления. Структуры управления можно помещать внутрь других структур, например блок ifThen внутрь цикла ForNext. Говорят, что структура управления, помещенная внутрь другой структуры, является вложенной. Глубина вложения управляющих структур не ограничена. Для улучшения читаемости кода принято смещать конструкции принятия решения или цикла в программе в случае использования вложенных структур управления. Например, следующая процедура печатает названия всех общих шрифтов для принтера и экрана. Заметим, что первый оператор Next закрывает внутренний цикл For, а последний оператор Next закрывает внешний цикл For. Точно так же и для вложенных операторов if, операторы End if автоматически применяются для закрытия ближайшего к нему оператора if. Вложенные структуры Do...Loop работают подобным же образом – самый дальний оператор Loop соответствует самому дальнему оператору Do.
Оператор Exit позволяет досрочно выходить из циклов For, Do и процедур Sub, Function. Синтаксис оператора Exit прост. Операторы Exit For внутри цикла For и Exit Do внутри цикла Do могут появляться сколь угодно раз. Оператор Exit Do работает со всеми разновидностями структуры цикла Do. Операторы Exit For и Exit Do применяются, когда необходимо завершить цикл немедленно, не продолжая дальнейших итераций или не ожидая выполнения блока операторов в теле цикла. Например, в предыдущем примере, который печатает общие шрифты для экрана и принтера, процесс сравнения продолжается даже в том случае, когда соответствие с каким-то шрифтом принтера уже найдено. В более эффективной версии этой процедуры при помощи оператора досрочного выхода организуется немедленный выход из цикла, как только найдено нужное соответствие. Как демонстрирует следующий пример, оператор Exit почти всегда используется внутри оператора структуры ветвления, создаваемой при помощи операторов If или Select Case, и вложенной в цикл.
При использовании оператора Exit для выхода из цикла значения переменной цикла зависят от того, каким образом завершается его выполнение.
При нормальном завершении цикла переменная цикла имеет значение на единицу больше верхней границы числа циклов.
При преждевременном завершении цикла переменная сохраняет свое значение, которое она получила с учетом обычных правил.
При завершении цикла по концу набора переменная цикла имеет значение Nothing (Ничего), если она является переменной типа object (Объект), или значение Empty (Пусто), если она является переменной типа Variant

Тема 13
Структура приложения. Техника написания кода
Предыдущие темы были посвящены описанию основных понятий и обзору системы программирования Visual Basic. Теперь мы приступим к систематическому изучению его языка. Создав интерфейс приложения с помощью форм и элементов управления, необходимо написать код, который определяет поведение приложения. Как и большинство современных языков программирования Visual Basic поддерживает общие конструкции программирования и языковые элементы. Он является объектно-ориентированным языком программирования. Понимание основных концепций объектного программирования помогает сделать процесс программирования легким и приятным делом. Если кто-то из вас уже программировал на других языках, то большая часть материала покажется знакомой. Хотя большинство конструкций Visual Basic похожи на соответствующие конструкции других языков, событийная его природа вносит свои различия.
13.1. Структура приложения
Приложение – это набор инструкций, заставляющий компьютер выполнять задачу. Структура приложения – это организация инструкций, т. е. хранение и порядок их выполнения. Простые приложения имеют простую структуру – организация не слишком важна для кода длиной в несколько строк. Для более сложных приложений необходимость организации или структуры приложения становится очевидной.
Приложение основано на объектах, поэтому структура программы отражает модель объектов и их взаимодействие. По определению объекты содержат данные и код. Формы, отображаемые на экране, представляет внешнюю модель объектов, т.е. интерфейс пользователя. Модель взаимодействия объектов скрыта от пользователя, но определяет содержание приложения, его внутреннее поведение. Для каждой формы существует связанный с ней модуль формы, который хранится в файле с расширением frm и содержит ее код.
Каждый модуль формы содержит процедуры обработки событий – раздел кода, куда помещаются инструкции, которые будут выполняться в ответ на определенные события. Формы могут содержать элементы управления. Для каждого элемента управления формы существует соответствующий набор процедур обработки событий в модуле формы, которые могут содержать процедуры общего характера, выполняемые в ответ на вызов от какой-либо процедуры обработки события. Код, не связанный с конкретной формой или элементом управления, помещается в другой тип модуль – стандартный модуль, хранимый в файле с расширением bas. Процедуру, которую можно использовать для ответа на события в нескольких различных объектах, предпочтительнее поместить в стандартный модуль, чем дублировать ее код в процедурах обработки событий для каждого объекта.
Модуль класса хранится в файле с расширением cls и используется для создания объектов, вызываемых из процедур разрабатываемого приложения. Стандартный модуль содержит только код, тогда как модуль класса содержит и код и данные – его можно представить как элемент управления без физического представления.
Если ранее рассматривалось, какие компоненты и как можно добавлять в приложение, то сейчас мы будем рассматривать вопросы написания кода в различных компонентах, чтобы они вместе создали приложение. По умолчанию проект содержит единственный модуль формы. При необходимости в приложение добавляются модули формы и класса и стандартные модули.
13.2. Как работает событийное приложение
Событие – это действие, распознаваемое формой или элементом управления. Событийные приложения выполняют код Basic в ответ на событие. Каждая форма и элемент управления имеют заранее определенный набор событий. Если происходит одно из этих событий и есть код в связанной с событием процедуре его обработки, активизируется выполнение этого кода. Хотя объекты автоматически распознают заранее определенный набор событий, только программист решает, надо ли отвечать на отдельное событие и как именно. Каждому событию соответствует раздел кода – процедура обработки события. Если необходимо, чтобы элемент управления реагировал на событие, следует написать соответствующий код в процедуре обработки события.
Типы событий, распознаваемых объектами, разнятся, но многие из них являются общими для большинства элементов управления. Например, большинство объектов распознает событие click (щелчок), если пользователь выполнил щелчок на форме, выполняется код из процедуры обработки события click формы; если пользователь нажал кнопку управления, выполняется код из процедуры обработки события click кнопки управления. Вероятно, что для каждого случая коды будут различны.
Вот типичная последовательность событий в приложении:
1. После запуска приложения загружается и отображается форма.
2. Форма (элемент управления) получает информацию о событии. Событие может быть вызвано пользователем (нажатие клавиши на клавиатуре), системой (событие, связанное с таймером) или косвенно кодом приложения (событие Load, когда код загружает форму).
3. Если существует код в соответствующей процедуре обработки события, он выполняется.
4. Приложение ожидает следующего события.
Встречаются события, связанные с другими событиями. Например, когда происходит событие DblCiick, происходят также события MouseDown, MouseUp и Click.
13.3. До начала кодирования
Наиболее важный (и часто упускаемый из вида) этап создания приложения – этап разработки. Если это очевидно для интерфейса пользователя приложения, то для структуры кода может и не быть таким очевидным. Структура приложения может повлиять на его эффективность, а также на удобство сопровождения и легкость в работе.
Код приложения имеет иерархическую структуру. Типичное приложение состоит из одного или более модулей: модуль формы для каждой формы приложения, необязательные стандартные модули для совместно используемого кода и необязательные модули класса. Каждый модуль содержит одну или более процедур, которые содержат код: процедуры обработки событий, процедуры Sub и Function и процедуры Property. Принадлежность процедур модулям зависит частично от типа создаваемого приложения. Так как в основе VB лежат объекты, это помогает думать о приложении в терминах объектов, которые его составляют.
Например, дизайн образца приложения Vcr.vbp, основан на объектах, которые представляют видеомагнитофон и телевизор. Приложение VCR (Видеомагнитофон) состоит из двух модулей форм, стандартного модуля и двух модулей классов. С помощью Object Browser (Просмотр объектов) можно исследовать структуру проекта (рис.). Главная форма приложения VCR (frmVCR) – визуальное представление комбинации видеомагнитофона и экрана телевизора (рис.). Она составлена из нескольких объектов, которые моделируют объекты реального мира. Группа кнопок управления (cmdPlay, cmdRecord и т. д.) имитирует кнопки управления магнитофоном. Программное обеспечение видеомагнитофона содержит также часы (IblTime), индикатор канала (IblChannel), функциональные индикаторы (shpPlay, shpRecord и т. д.) и экран для вывода графических данных (picTV). Процедуры обработки событий для всех этих объектов содержатся в модуле формы Vcr.frm. Во многих случаях существуют процедуры, выполняемые без завершения, которые используются совместно более чем одним объектом. Например, когда кнопки Play, Rewind или Record нажаты, кнопки Pause и Stop должны быть разрешены (их можно нажать в любой момент). Вместо того чтобы дублировать этот код в каждой процедуре обработки события Click каждой кнопки, лучше создать совместно используемую процедуру Sub, которая может быть вызвана любой кнопкой. Если потребуется в будущем модернизировать эти программы, все модификации будут произведены в одном месте. Эта и другие совместно используемые процедуры, содержатся в стандартном модуле Vcr.bas. Некоторые части видеомагнитофона невидимы, например, лентопротяжный механизм или логическая схема записи телевизионных программ. Также и некоторые функции программного обеспечения видеомагнитофона не имеют визуального представления. Все это осуществлено в виде двух модулей классов: Recorder.cis и Таре.els. Код для инициирования процесса записи содержится в модуле cisRecorder; код, задающий направление движения и скорость ленты, содержится в модуле cisTape. Классы, определенные в этих модулях, не имеют прямых ссылок ни на один из объектов формы. Так как они являются независимыми модулями кода, их можно было бы использовать без изменений для построения аудиомагнитофона.
В добавление к процессу разработки структуры кода приложения, важно установить соглашения об использовании имен. По умолчанию первой форме проекта дается имя Form1, второй – Form2 и т. д. Если в приложении несколько форм, следует дать им имеющие смысл названия во избежание путаницы при написании и редактировании кода.
13.4. Техника написания кода
Как и в любом другом языке программирования, в VB имеются собственные правила организации, редактирования связей и форматирования программ. Программы VB хранятся в модулях. Существует три вида модулей: модули формы и класса, стандартный модуль. Простые приложения могут состоять из одного модуля формы, и весь программный код приложения находится в нем. При дальнейшей модификации по мере увеличения размеров приложения в них добавляются дополнительные модули формы. Со временем обнаруживается, что в приложении появляется некоторый общий программный код, выполняемый в нескольких модулях формы. Дублирование этого кода в каждом соответствующем модуле формы неэффективно, поэтому создается отдельный модуль, содержащий процедуру, выполняющую этот общий код. Такой отдельный модуль должен быть стандартным модулем. Через какое-то время можно создать библиотеку совместно используемых модулей. Каждый стандартный модуль, модуль формы или класса может содержать:
объявления констант, типов, переменных и процедур из динамически подключаемых библиотек (DLL), используемых на уровне модуля;
процедуры Sub (подпрограмма), Function (функция) и Property (свойство), представляющие собой некоторый программный код, выполняемый как одно целое.
Модули формы являются основой большинства приложений. Они могут состоять из процедур обработки событий, процедур общего характера и объявлений переменных, констант, типов и внешних процедур, используемых на уровне модуля формы. Если просмотреть модуль формы в текстовом редакторе, то можно увидеть в нем также описания формы и ее элементов управления, включая установки относящихся к ним свойств. Программный код, создаваемый в модуле формы, относится только к конкретному приложению, которому принадлежит модуль. Однако в нем можно ссылаться и на другие формы и объекты приложения.
Стандартные модули являются хранилищами процедур и объявлений, которые доступны для других модулей приложения. Они могут содержать глобальные (доступные всему приложению) или локальные (доступные на уровне модуля) объявления переменных, констант, типов, внешних процедур и процедур общего характера. Если не ссылаться на формы и элементы управления по имени, то стандартный модуль можно использовать в разных приложениях.
Модули классов являются основой объектно-ориентированного программирования. Для создания новых объектов соответствующий им программный код помещается в модули классов. Эти новые объекты могут включать в себя специальные разработанные программистом свойства и методы. В действительности формы являются модулями классов, которые могут содержать помещенные в них элементы управления и отображать окна формы.
При запуске Редактора кода (Code Editor) появляется окно, в котором можно вводить текст программы (программный код). В какой-то мере редактор похож на специализированный текстовый процессор с набором функций, облегчающих ввод текста программы на языке Visual Basic. Так как работа с программным кодом осуществляется в модулях, то для каждого модуля, выбранного в Project Explorer (Проводник проекта), создается отдельное окно Code Editor. Код внутри каждого модуля разделен на отдельные секции (sections) для каждого объекта, содержащегося в модуле. Переключение между секциями осуществляется с помощью списка Object Listbox (Список объектов). В модуле формы этот список содержит общую секцию, секцию для самой формы и секцию для каждого элемента управления на данной форме. Для модуля класса список включает общую секцию и секцию класса, для стандартного модуля – только общую секцию.
Каждая секция может содержать несколько различных процедур, доступ к которым обеспечивается с помощью списка Procedure Listbox (Список процедур). Список процедур для модуля формы содержит отдельную секцию для каждой процедуры обработки события формы или элемента управления. Например, для элемента Label он включает в себя секции для событий change (Изменить), Сlick (Щелчок) и DblClick (Двойной щелчок). Список процедур для модуля класса содержит только процедуры событий для самого класса – Initialize (Инициализировать) и Terminate (Завершить). Для стандартных модулей не существует списка процедур событий, так как стандартный модуль не поддерживает события.
Список процедур для общей секции модуля содержит единственный выбор – секцию Declarations (Объявлений), в которую заносятся объявления локальных (доступных только данному модулю) переменных, констант и библиотек динамической компоновки (DLL). При добавлении процедур Sub или Function в модуль они также добавляются в список Procedure Listbox после секции Declarations.
В окне редактора Code Editor код может отображаться по разному. Можно выбрать режим, при котором отображается только одна процедура, или режим отображения всех процедур. В последнем случае процедуры отделяются друг от друга горизонтальной линией. Переключение между двумя этими возможностями происходит с помощью кнопок View Selection (Выбор вида), расположенных в левом нижнем углу окна редактора.
13.5. Автоматизация написания программы
VB делает написание программ приятным и легким процессом, позволяя автоматически вносить операторы, свойства и параметры в текст программы, при наборе которого редактор отображает список подходящих операторов, прототипов функций или значений. Включение или отключение этой и других возможностей работы с текстом осуществляется с помощью вкладки Editor (Редактор) диалога Options (Опции), вызываемого командой Options меню Tools (Инструменты).
При вводе имени элемента управления появляется раскрывающийся список с его свойствами. Эта возможность обеспечивается средством Auto List Members (Члены автоматического списка). При наборе первых нескольких букв имени свойства, оно автоматически будет выбрано в списке; нажатие клавиши Таb завершит его набор. Эта возможность полезна также, если пользователь не знает точно, какие свойства доступны данному элементу управления. Если эта возможность отключена, ее всегда можно включить комбинацией клавиш Ctrl+J.
Средство Auto Quick Info (Быстрая автоматическая информация) отображает синтаксис операторов и функций. При вводе правильного оператора или правильного имени функции под текущей строкой отображается синтаксис оператора или функции с выделенным полужирным шрифтом первым параметром. После ввода этого параметра полужирным шрифтом выделяется второй и т. д. Эту возможность можно включить комбинацией клавиш Ctrl+I.
С помощью закладок (Bookmarks) можно отмечать строки кода в Code Editor, чтобы позже при необходимости вернуться к этим строкам. Команды установки и снятия закладок, а также для перемещения по существующим закладкам доступны из пункта Bookmarks (Закладки) меню Edit (Правка) или из панели инструментов Edit (Правка).
Литература
В.Н. Агафонов. Спецификация программ: понятийные средства и их организация. – Новосибирск: Наука (Сибирское отделение), 1987.
Ю.М. Безбородов. Индивидуальная отладка программ. – М.: Наука, 1982.
Г. Буч. Объектно-ориентированное проектирование с примерами применения. – М.: Конкорд, 1992.
Ф.П. Брукс, мл. Как проектируются и создаются программные комплексы. – М.: Наука, 1979.
Б. Боэм, Дж. Браун, Х. Каспар и др. Характеристики качества программного обеспечения. – М.: Мир, 1981.
Н.Вирт. Систематическое программирование. – М.: Мир, 1977.
У. Дал, Э. Дейкстра, К. Хоор. Структурное программирование. – М.: Мир, 1975.
Е.А. Жоголев. Технологические основы модульного программирования // Программирование, 1980, #2.
Е.А. Жоголев. Введение в технологию программирования (конспект лекций). – М.: "ДИАЛОГ-МГУ", 1994.
К. Зиглер. Методы проектирования программных систем. – М.: Мир, 1985.
М. Зелковец, А. Шоу, Дж. Гэннон. Принципы разработки программного обеспечения. – М.: Мир, 1982.
Информатика: Учебн. пособие для пед. спец. высш. учеб. заведений / А.Р. Есаян, В.И. Ефимов, Л.П. Лапицкая и др – М.: Просвещение, 1991. – 288 с.
В.Ш. Кауфман. Языки программирования. Концепции и принципы. – М.: Радио и связь, 1993.
В.В. Липаев. Тестирование программ. – М.: Радио и связь, 1986.
В.В. Липаев. Качество программного обеспечения. – М.: Финансы и статистика, 1983.
Г.Майерс. Надежность программного обеспечения. – М.: Мир, 1980.
Острейковский В.А. Информатика: Учеб. для вузов. – М.: Высш. шк., 1999.
Д. Ван Тассел. Стиль, разработка, эффективность, отладка и испытание программ. – М.: Мир, 1985.
В. Турский. Методология программирования. – М.: Мир, 1981.
Б. Шнейдерман. Психология программирования. – М.: Радио и связь, 1984.
Дж. Хьюз, Дж. Мичтом. Структурный подход к программированию. – М.: Мир, 1980.
Дж. Фокс. Программное обеспечение и его разработка. – М.: Мир, 1985.
А.Л.Фуксман. Технологические аспекты создания программных систем. – М.: Статистика, 1979.
Т. Бадд. Объектно-ориентированное программирование в действии. – СПб.: «Питер», 1997. – 464 с.
Г. Буч. Объектно-ориентированный анализ и проектирование с примерами приложений на С++. – М., СПб.: «Бином», «Невский диалект», 1998. – 560 с.
И. Грэхем. Объектно-ориентированные методы. Принципы и практика. – М.: «Вильямс», 2004. – 880 с.
А. Синтес. Освой самостоятельно объектно-ориентированное программирование за 21 день. – М.: «Вильямс», 2002. – 672 с.
Ресселман Боб, Писли Ричард и др. Использование Visual Basic 6.: Пер. с англ. – К.; М.; СПБ,: Издательский дом "Вильямс", 1999. – 608 с.
Сайлер, Брайан, Споттс, Джефф. Использование Visual Basic 6. Специальное издание: Пер. с англ. – М.; СПб.; К.; Издательский дом "Вильямс", 2000. – 832 с.
Гарнаев А.Ю. Excel, VBA, Internet в экономике и финансах. – СПб.: БХВ-Петербург, 2001. – 816 с.
Visual Basic 6.0: пер. с англ. – СПб.: БХВ – Санкт-Петербург, 1999. – 992 с.
Дьяков В.П. Справочник по алгоритмам и программам на языке Бейсик для персональных ЭВМ. – М.: Наука, 1987.
Иодан Э. Структурное проектирование и конструирование программ. – М.: Мир, 1979.
Гудман С., Хидитниеми С. Введение в разработку и анализ алгоритмов. – М.: Мир, 1981.
Мейер Б., Бодуэн К. Методы программирования. – М.: Мир, 1982.
Заварыкин В.М., Житомирский В.Г., Лапчик М.П. Техника вычислений и алгоритмизация. – М.: Просвещение, 1987.
Лапчик М.П. Вычисления. Алгоритмизация. Программирование – М.: Просвещение, 1988.

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









13PAGE 15


13PAGE 14415



Требования к ПС

Руководство
по применению ПС

Тексты
программ

Внешнее
описание ПС

Спецификация языка программирования

Спецификация
аппаратуры

Спецификация
базового
программного
обеспечения

Рис 1. Грубая схема разработки и применения ПС

Рис. 2. Модель перевода

M

W

R

Представление В

Представление А

Стадия производства программных изделий

Стадии эксплуатации

Этапы разработки

Фаза применения

Фаза сопровождения

Внешнее описание

Конструирование

Кодирование

Аттестация

Рис. 3. Стадии, этапы и фазы жизненного цикла программного средства

8, 9, 10, 11, 12,

4, 5, 6, 7

2, 3

1

3

2

1

0

9





4



3

1

5

17

Спецификация программы (головного модуля)

Текст головного модуля

Спецификация
1-ой подзадачи

Спецификация
2-ой подзадачи

Спецификация
3-ей подзадачи

Рис. 7. Первый шаг формирования модульной структуры программы

Нижний уровень

Шаг 1

Текст головного модуля
2-ой подзадачи

Спецификация 2-ой подзадачи

Текст головного модуля
3-ей подзадачи

Спецификация 3-ей подзадачи

Текст головного модуля
1-ой подзадачи

Спецификация 1-ой подзадачи

Спецификация
2.2-ой подзадачи

Спецификация
2.1-ой подзадачи

Рис. 8. Второй шаг формирования модульной структуры программы

Рисунок. Блок-схема перебора расстановок ферзей

Целенаправленная
конструктивная реализация

Методы разработки структуры программ

Восходящие

Нисходящие

Конструктивная реализация

Конструктивная разработка

Конструктивный подход

Нисходящая реализация

Нисходящая разработка

Классический подход

Архитектурная реализация

Архитектурная разработка

Архитектурный подход

Восходящая реализация
(не рекомендуется)

Восходящая разработка
(не рекомендуется)

Классический подход

13 EMBED Visio.Drawing.5 1415

Нет

Да

P

S

Да

Нет

P

S1

S2

Разветвление

S1

S2

Следование

Рис. 10. Основные управляющие конструкции структурного программирования

Повторение

Рис. 11. Основные конструкции
структурного программирования
на псевдокоде

Следование:
обобщенный оператор
обобщенный оператор
Разветвление:
ЕСЛИ условие ТО
обобщенный оператор
ИНАЧЕ
обобщенный оператор
ВСЕ ЕСЛИ
Повторение:
ПОКА условие ДЕЛАТЬ
обобщенный оператор
ВСЕ ПОКА

ИСКЛЮЧЕНИЕ имя исключения
обобщенный оператор
ВСЕ ИСКЛЮЧЕНИЕ

Выход из повторения (цикла):
ВЫЙТИ
Выход из процедуры (функции):
ВЕРНУТЬСЯ
Переход на обработку исключительной ситуации:
ВОЗБУДИТЬ имя исключения

Рис. 12. Частные случаи оператора перехода

УДАЛЕНИЕ В ФАЙЛЕ ЗАПИСЕЙ ДО ПЕРВОЙ, УДОВЛЕТВОРЯЮЩЕЙ ЗАДАННОМУ ФИЛЬТРУ:
УСТАНОВИТЬ НАЧАЛО ФАЙЛА.
ПОКА НЕ КОНЕЦ ФАЙЛА ДЕЛАТЬ
ПРОЧИТАТЬ ОЧЕРЕДНУЮ ЗАПИСЬ.
ЕСЛИ ОЧЕРЕДНАЯ ЗАПИСЬ УДОВЛЕТВОРЯЕТ ФИЛЬТРУ ТО
ВЫЙТИ
ИНАЧЕ
УДАЛИТЬ ОЧЕРЕДНУЮ ЗАПИСЬ ИЗ ФАЙЛА.
ВСЕ ЕСЛИ
ВСЕ ПОКА
ЕСЛИ ЗАПИСИ НЕ УДАЛЕНЫ ТО
НАПЕЧАТАТЬ "ЗАПИСИ НЕ УДАЛЕНЫ".
ИНАЧЕ
НАПЕЧАТАТЬ "УДАЛЕНО n ЗАПИСЕЙ".
ВСЕ ЕСЛИ

Рис. 13. Пример одного шага детализации на псевдокоде

1

4

1

2

2

2

1

2

3

4

5

0

3

1

8

7

6

5

4

3

2

Корень

Уровень 1

Уровень 2

Уровень 8

1

Запись решения и его номера

i=i-1

k=k+1

i>n

j=0, i=i+1

n=8, i=0, k=0

Начало

i - номер хода,
k – количество
решений,
i( n, j( n

Ввод начальных данных

Прописка варианта

ВПЕРЕД

Вариант
подходит

i>n

j=j+1

Нет

Нет

ВБОК

Да

Нет

Выписка последнего варианта и хода, восстановление текущего
варианта и предыдущего хода

Да

НАЗАД

1

i>n

Да

Конец

Нет

Dim позиция() As Integer, горизонт() As Boolean, восход() As Boolean, заход() As Boolean
Dim k As Integer
Const n As Integer = 8, n2 As Integer = 2 * n
Sub Ферзи() 'Рекурсивный вариант
Dim m As Integer
ReDim позиция(1 To n), горизонт(1 To n), восход(2 To n2), заход(-n + 1 To n - 1)
k = 0: For m = 1 To n: горизонт(m) = True: Next m
For m = 2 To n2: восход(m) = True: Next m: For m = -n + 1 To n - 1: заход(m) = True: Next m
Try(1): MsgBox "Только " & Str(k) & " вариантов"
End Sub
Function Try(i As Integer)
Dim m As Integer, j As Integer, var As String
For j = 1 To n
If (горизонт(j) = True) And (восход(i + j) = True) And (заход(i - j) = True) Then
If i < n Then
горизонт(j) = False: восход(i + j) = False: заход(i - j) = False: позиция(i) = j
Try(i + 1): горизонт(j) = True: восход(i + j) = True: заход(i - j) = True
Else
k = k + 1: var = "Ход " & Str(k) & ". Решение:"
For m = 1 To n: var = var & " " & Str(позиция (m)) & ",": Next m: MsgBox var
End If
End If
Next j
End Function

(i,j)

8
7
6
5
4
3
2
1
0

10

1

16

0 1 2 3 4 5 6 7 8

16

10

1

Sub Ферзи()
Dim позиция() As Integer, горизонт() As Boolean, восход() As Boolean, заход() As Boolean
Dim i As Integer, j As Integer, k As Integer, m As Integer, var As String
Const n As Integer = 8, n2 As Integer = 16
ReDim позиция(1 To n), горизонт(1 To n), восход(1 To n2), заход(1 To n2)
i = 0: k = 0: For m = 1 To n: горизонт(m) = False: Next m
For m = 1 To n2: восход(m) = False: заход(m) = False: Next m
вперед: i =i +1: j = 0
If i > n Then GoTo резул
вбок: j = j + 1: If j > n Then GoTo назад
If (горизонт(j) = True) Or (восход(n + j - i) = True) Or (заход(j + i) = True) Then GoTo вбок
горизонт(j) = True: восход(n + j - i) = True: заход(j + i) = True: позиция(i) = j: GoTo вперед
резул: k = k + 1: var = "Ход " & Str(k) & ". Решение:"
For m = 1 To n: var = var & " " & Str(позиция (m)) & ",": Next m: MsgBox var
назад: i = i – 1: If I =0 Then GoTo конец
j = позиция(i): горизонт(j) = False: восход(n + j - i) = False: заход(j + i) = False: GoTo вбок
конец: MsgBox "Только " & Str(k) & " вариантов"
End Sub

1

4

3

5

2


1
2
3
4
5

1
(
18
28
22
24

2
4
(
12
28
29

3
22
19
(
8
9

4
7
49
18
(
9

5
29
16
10
10
(



H

( ( 28 ( (
( ( ( ( 29
( ( ( 8 (
( 49 ( ( (
29 ( ( ( (

( ( 28 ( (
( ( ( ( 29
( 19 ( ( (
7 ( ( ( (
( ( ( 10 (

( ( 28 ( (
( ( ( ( 29
( 19 ( 8 (
7 49 ( ( (
29 ( ( 10 (

( ( 28 ( (
( ( ( 28 (
( ( ( ( 9
7 ( ( ( (
( 16 ( ( (

( ( 28 ( (
( ( ( 28 (
( 19 ( ( (
( ( ( ( 9
29 ( ( ( (

( ( 28 ( (
( ( ( 28 (
( 19 ( ( 9
7 ( ( ( 9
29 16 ( ( (

( ( 28 ( (
( ( ( 28 29
( 19 ( 8 9
7 49 ( ( 9
29 16 ( 10 (

( ( 28 ( (
4 ( ( ( (
( ( ( ( 9
( 49 ( ( (
( ( ( 10 (

( ( 28 ( (
4 ( ( ( (
( ( ( 8 (
( ( ( ( 9
( 16 ( ( (

( ( 28 ( (
4 ( ( ( (
( ( ( 8 9
( 49 ( ( 9
( 16 ( 10 (

( ( 28 ( (
4 ( ( 28 29
( 19 ( 8 9
7 49 ( ( 9
29 16 ( 10 (

( ( 28 22 24
4 ( 12 28 29
22 19 ( 8 9
7 49 18 ( 9
29 16 10 10 (

B

G

I

J

K

L

B

( 18 ( ( (
( ( ( ( 29
( ( ( 8 (
7 ( ( ( (
( ( 10 ( (

( 18 ( ( (
( ( ( ( 29
22 ( ( ( (
( ( 18 ( (
( ( ( 10 (

( 18 ( ( (
( ( ( ( 29
22 ( ( 8 (
7 ( 18 ( (
( ( 10 10 (

( 18 ( ( (
( ( ( 28 (
( ( ( ( 9
( ( 18 ( (
29 ( ( ( (

( 18 ( ( (
( ( ( 28 (
22 ( ( ( (
( ( ( ( 9
( ( 10 ( (

( 18 ( ( (
( ( ( 28 (
22 ( ( ( 9
( ( 18 ( 9
29 ( 10 ( (

( 18 ( ( (
( ( ( 28 29
( ( ( 8 9
7 ( 18 ( 9
29 ( 10 10 (

( 18 ( ( (
( ( 12 ( (
( ( ( ( 9
7 ( ( ( (
( ( ( 10 (

( 18 ( ( (
( ( 12 ( (
( ( ( 8 (
( ( ( ( 9
29 ( ( ( (

( 18 ( ( (
( ( 12 ( (
( ( ( 8 9
7 ( 18 ( 9
29 ( ( ( (

( 18 ( ( (
( ( 12 28 29
22 ( ( 8 9
7 ( 18 ( 9
29 ( ( 10 (

( 18 28 22 24
4 ( 12 28 29
22 19 ( 8 9
7 49 18 ( 9
29 16 10 10 (

X

A

C

D

E

F

Дерево полного перебора (начало)

Шаг 2

Шаг 3

Шаг 4

1

1

1

4

1

1

3

1

3

1

12

1

8

14

9

1

2

3

4

5

6

Sub Шар_Прокол ()
Шар.Спустить
Шар.Звук "Бах!"
Шар.Надуть = False
Шар.Диаметр = 0
End Sub

Шар.Надуть
Шар.Спустить
Шар.Подъем 5

Шар.Цвет = Красный
Шар.Диаметр = 10
Шар.Надут = True

7

12

11

10

9

8

Dim A() As Integer: Const n As Integer = 20
Sub Пузырьковая_сортировка ()
Dim i As Integer, j As Integer, m As Integer, var As String
ReDim A (1 To n): var = "Исходные:"
For i = 1 To n: A(i) = Int(Rnd(Time)*100): var = var & " " & Str(A (i)): Next i: MsgBox var
For i = 2 To n: For j = n To i Step -1
If A(j-1) > A(j) Then
m = A(j-1): A(j-1) = A(j): A(j) = m
End If
Next j: Next i
var = "Отсортированные:":For i = 1 To n: var = var & " " & Str(A (i)): Next i: MsgBox var
End Sub

Адресная сортировка: 7,2 3 8 4 8 5,14 9 1
5 2 6 3 7 4 8 1

(
0
10
4
5

0
(
8
24
24

14
11
(
0
0

0
42
11
(
1

19
6
0
0
(



(
0
10
4
6

0
(
8
24
25

14
11
(
0
1

0
42
11
(
2

19
6
0
0
(

h6=h7=h8=h9=0, h10=1



(
18
28
22
24
h1=18

4
(
12
28
29
h2=4

22
19
(
8
9
h3=8

7
49
18
(
9
h4=7

29
16
10
10
(
h5=10



Приведение матрицы по строкам и столбцам

( ( ( ( 24
( ( ( 28 (
( 19 ( ( (
7 ( ( ( (
29 ( 10 ( (

( ( ( ( 24
( ( ( 28 (
22 ( ( ( (
( ( 18 ( (
( 16 ( ( (

( ( ( ( 24
( ( ( 28 (
22 19 ( ( (
7 ( 18 ( (
( 16 10 ( (

( ( ( ( 24
( ( 12 ( (
( ( ( 8 (
7 ( ( ( (
( 16 ( ( (

( ( ( ( 24
( ( 12 ( (
22 ( ( ( (
( 49 ( ( (
( ( ( 10 (

( ( ( ( 24
( ( 12 ( (
22 ( ( 8 (
7 49 ( ( (
( 16 ( 10 (

( ( ( ( 24
( ( 12 28 (
22 19 ( 8 (
7 49 18 ( (
( 16 10 10 (

( ( ( ( 24
4 ( ( ( (
( ( ( 8 (
( 49 ( ( (
( ( 10 ( (

( ( ( ( 24
4 ( ( ( (
( 19 ( ( (
( ( 18 ( (
( ( ( 10 (

( ( ( ( 24
4 ( ( ( (
( 19 ( 8 (
( 49 18 ( (
( ( 10 10 (

( ( ( ( 24
4 ( 12 28 (
22 19 ( 8 (
7 49 18 ( (
( 16 10 10 (

N

S

T

U

V

N

( ( ( 22 (
( ( ( ( 29
( 19 ( ( (
( ( 18 ( (
29 ( ( ( (

( ( ( 22 (
( ( ( ( 29
22 ( ( ( (
( 49 ( ( (
( ( ( 10 (

( ( ( 22 (
( ( ( ( 29
22 19 ( ( (
( 49 18 ( (
29 ( 10 ( (

( ( ( 22 (
( ( 12 ( (
( ( ( ( 9
( 49 ( ( (
29 ( ( ( (

( ( ( 22 (
( ( 12 ( (
22 ( ( ( (
( ( ( ( 9
( 16 ( ( (

( ( ( 22 (
( ( 12 ( (
22 ( ( ( 9
( 49 ( ( 9
29 16 ( ( (

( ( ( 22 (
( ( 12 ( 29
22 19 ( ( 9
( 49 18 ( 9
29 16 10 ( (

( ( ( 22 (
4 ( ( ( (
( ( ( ( 9
( ( 18 ( (
( 16 ( ( (

( ( ( 22 (
4 ( ( ( (
( 19 ( ( (
( ( ( ( 9
( ( 10 ( (

( ( ( 22 (
4 ( ( ( (
( 19 ( ( 9
( ( 18 ( 9
( 16 10 ( (

( ( ( 22 (
4 ( 12 ( 29
22 19 ( ( 9
7 ( 18 ( 9
29 16 10 ( (

( ( ( 22 24
4 ( 12 28 29
22 19 ( 8 9
7 49 18 ( 9
29 16 10 10 (

H

M

O

P

Q

R

Дерево полного перебора (конец)

Рис. 14. Спектр подходов
к проектированию тестов.

Рациональная
стратегия

Тестирование
по отношению
к тексту
программы

Тестирование
по отношению
к спецификациям

76

72

58

(
0
(
(
(

(
(
0
(
(

(
(
(
(
0

0
(
(
(
(

(
(
(
0
(



(
0
(
(
(

(
(
(
(
(

(
(
(
0
0

0
(
(
(
1

19
(
(
0
(



(
0
(
(
(

(
(
0
16
16

14
(
(
0
0

0
(
11
(
1

19
(
0
0
(



(
0
10
4
5

0
(
8
24
24

14
11
(
0
0

0
42
11
(
1

19
6
0
0
(



56

56

56

48

Перебор вариантов по алгоритму ветвей и границ

Уровень Узлы

3

17

3

9

12

9

4

4

5

1

1

8

14

9

9

3

3

3

4

8

4

3

3

(


3

17

3

9

12

9

4

4

5

(

8

8

14

9

9

90

8

5

6

1

3

2

70

9

7

11

Dim S() As Integer
Const n As Integer = 8
Sub Пирамидальная_сортировка() 'Отладочный вариант
Dim j As Integer, m As Integer, k As Integer, var As String
ReDim S (1 To n): S(1)=23: S(2)=77: S(3)=12: S(4)=7: S(5)=44: S(6)=82: S(7)=16: S(8)=53
'For j = 1 To n: S(j) = Int(Rnd(Time)*100: Next j
k = n: var = "Исходные:": For j = 1 To n: var = var & " " & Str(S(j)): Next j: MsgBox var
For j = n\2 To 1 Step -1
var = "Пирамида:": For m = 1 To n: var = var & " " & Str(S(m)): Next m: MsgBox var
просеивание j, k
Next j
For k = n - 1 To 1 Step -1: m = S(1): S(1) = S(k+1): S(k+1) = m
var = "Сортировка:": For j = 1 To n: var = var & " " & Str(S(j)): Next j: MsgBox var
просеивание 1, k
Next k
var = "Отсортированные:": For j = 1 To n: var = var & " " & Str(S(j)): Next j: MsgBox var
End Sub
Sub просеивание(x As Integer, k As Integer)
Dim m As Integer, y As Integer
1: y = x + x
If y > k Then Exit Sub
If y = k Then GoTo 2
If S(y) < S(y + 1) Then y = y + 1 ' > - по не возрастанию
2: If S(x) >=S(y) Then Exit Sub '<= - по не возрастанию
m = S(x): S(x) = S(y): S(y) = m: x = y: GoTo 1
End Sub

6

17

23

8

14

25

6

3

30

7

Dim S() As Integer
Const n As Integer = 10
Sub Быстрая_сортировка() 'Отладочный вариант
Dim T1(1 To 13) As Integer, T2(1 To 13) As Integer
Dim i As Integer, j As Integer, k As Integer, a As Integer, b As Integer, x As Integer, var As String
ReDim S(1 To n): S(1)=6: S(2)=23: S(3)=17: S(4)=8: S(5)=14: S(6)=25: S(7)=6: S(8)=3: S(9)=30: S(10)=7
'For j = 1 To n: S(j) = Int(Rnd(Time) * 1000): Next j
var = "Исходные:": For j = 1 To n: var = var & " " & Str(S(j)): Next j: MsgBox var
k = 1: T1(1) = 1: T2(1) = n: 'Инициализация стека
Do: a = T1(k): b = T2(k): k = k – 1 'Чтение из стека (выбор адресов не отсортированной правой части)
Do: i = a - 1: j = b + 1: x = S((a + b)\2) 'Разделение массива или его части
Do: Do: i = i + 1: Loop While S(i) < x: Do: j = j - 1: Loop While x < S(j)
If i >= j Then 'Смыкание или перехлест границ частей массива
If i <> j Then i = i – 1 'Раздвижка границ
j = j + 1: GoTo 1
Else
Swap S(i), S(j) 'Обмен "чужих" на "своих"
End If
Loop While j - i > 2
If j - i = 2 Then 'Выяснение граничной ситуации
If S(i + 1) < x Then 'Люфт границ
i = i + 1
Else 'Четкое разделение границ
j = j - 1
End If
End If
1: If j < b Then 'Правая часть массива не исчерпана
k = k + 1: T1(k) = j: T2(k) = b 'Запись в стек (фиксация не отсортированной правой части)
End If
b = i 'Фиксация правой границы еще не отсортированной левой части
Loop While a < b 'Левая часть не исчерпана
Loop While k > 0 'Переход к анализу правой части
var = "Отсортированные:": For j = 1 To n: var = var & " " & Str(S(j)): Next j: MsgBox var
End Sub
Sub Swap(ByRef x As Integer, ByRef y As Integer) 'Обмен значениями
Dim m As Integer
m = x: x = y: y = m
End Sub

6 7 3 8 6 25 14 17 30 23.

Dim S() As Integer: Const n As Integer = 10, K As Integer = 11
Sub Бинарный_поиск() 'Отладочный вариант
Dim i As Integer, a As Integer, b As Integer, var As String
ReDim S(1 To n): S(1)=2: S(2)=7: S(3)=8: S(4)=9: S(5)=13: S(6)=15: S(7)=16: S(8)=17: S(9)=18: S(10)=23
var = "Исходные:": For j = 1 To n: var = var & " " & Str(S(j)): Next j: MsgBox var: a = 1: b = n:
1: If b MsgBox "Неудача": Exit Sub
Else
i = (a + b)\2
If K = S(i) Then: MsgBox "Адрес: " & Str(i) & ". Значение: " & Str(S(i)) & ". Ключ: " & Str(K): Exit Sub
Else: If K < S(i) Then: b = i – 1: Else: a = i + 1: End If
End If
GoTo 1
End If
End Sub

2

3

1

3

1

2

5

2

4

3

1

1

5

3

2

4

7

6

8

5

9

3

1


Дуги
d


x
y


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
1
1
3
3
4
5
6
6
6
6
7
7
8
9
3
7
6
4
6
5
9
4
8
5
9
8
6
9
5
3
2
5
4
1
2
1
2
3
5
2
3
1
1
3




13 EMBED Equation.3 1415

1
2
3
4
5
6
7
8
9
1
(
4
6
7
8
12
14
15



x = 6

t


Дуги
d


x
y


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1
1
1
3
3
4
5
6
6
6
6
7
7
8
9
3
7
6
4
6
5
9
4
8
5
9
8
6
9
5
3
2
5
4
1
2
1
2
3
5
2
3
1
1
3



x = 9


13 EMBED Equation.3 1415

1
2
3
4
5
6
7
8
9
(
(
1
4
6
3
2
9
7




13 EMBED Equation.3 1415




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(
(
5
8
13
10
11
(
12
15
14
(
(
(
(



Dim S() As Integer, A() As Integer: Const n As Integer = 15, m As Integer = 9
Sub Справочник_A() 'Отладочный вариант
Dim i As Integer, var As String
ReDim S(1 To n, 2), A(1 To m)
S(1,0)=1: S(2,0)=1: S(3,0)=1: S(4,0)=3: S(5,0)=3: S(6,0)=4: S(7,0)=5: S(8,0)=6
S(9,0)=6: S(10,0)=6: S(11,0)=6: S(12,0)=7: S(13,0)=7: S(14,0)=8: S(15,0)=9
For i = n To 1 Step -1: A(S(i,0)) = i: Next i
var = "Справочник A:": For i = 1 To m: var = var & " " & Str(A(i)): Next i: MsgBox var
End Sub

Dim S() As Integer, B() As Integer, C() As Integer: Const n As Integer = 15, m As Integer = 9
Sub Справочники_B_C() 'Отладочный вариант
Dim i As Integer, var As String: ReDim S(1 To n, 2), B(1 To m), C(1 To n)
S(1,0)=1: S(2,0)=1: S(3,0)=1: S(4,0)=3: S(5,0)=3: S(6,0)=4: S(7,0)=5: S(8,0)=6
S(9,0)=6: S(10,0)=6: S(11,0)=6: S(12,0)=7: S(13,0)=7: S(14,0)=8: S(15,0)=9
S(1,1)=3: S(2,1)=7: S(3,1)=6: S(4,1)=4: S(5,1)=6: S(6,1)=5: S(7,1)=9: S(8,1)=4
S(9,1)=8: S(10,1)=5: S(11,1)=9: S(12,1)=8: S(13,1)=6: S(14,1)=9: S(15,1)=5
For i = n To 1 Step -1: C(i) = B(S(i,1)): B(S(i,1)) = i: Next i
var = "Справочник B:": For i = 1 To m: var = var & " " & Str(B(i)): Next i: MsgBox var
var = "Справочник C:": For i = 1 To n: var = var & " " & Str(C(i)): Next i: MsgBox var
End Sub

Dim S() As Integer, A() As Integer, B() As Integer, C() As Integer
Const n As Integer = 15, m As Integer = 9
Sub Справочники_A_B_C() 'Отладочный вариант
Dim i As Integer, var As String
ReDim S(1 To n, 2), A(1 To m), B(1 To m), C(1 To n)
S(1,0)=1: S(2,0)=1: S(3,0)=1: S(4,0)=3: S(5,0)=3: S(6,0)=4: S(7,0)=5: S(8,0)=6
S(9,0)=6: S(10,0)=6: S(11,0)=6: S(12,0)=7: S(13,0)=7: S(14,0)=8: S(15,0)=9
S(1,1)=3: S(2,1)=7: S(3,1)=6: S(4,1)=4: S(5,1)=6: S(6,1)=5: S(7,1)=9: S(8,1)=4
S(9,1)=8: S(10,1)=5: S(11,1)=9: S(12,1)=8: S(13,1)=6: S(14,1)=9: S(15,1)=5
For i = n To 1 Step -1: C(i) = B(S(i,1)): A(S(i,0)) = i: B(S(i,1)) = i: Next i
var = "Справочник A:": For i = 1 To m: var = var & " " & Str(A(i)): Next i: MsgBox var
var = "Справочник B:": For i = 1 To m: var = var & " " & Str(B(i)): Next i: MsgBox var
var = "Справочник C:": For i = 1 To n: var = var & " " & Str(C(i)): Next i: MsgBox var
End Sub

Dim S() As Integer
Const n As Integer = 4
Sub Генератор_перестановок() 'Отладочный вариант
Dim i As Integer, j As Integer, z As Integer, y As Integer, l As Integer, var As String: ReDim S(1 To n)
For i = 1 To n: S(i) = n + 1 - i: Next i: z = 1: For i = 1 To n: z = z * i: Next i: Фиксация(1)
For y = 2 To z
i = 2: j = 1:While S(i-1)<=S(i): i = i + 1: Wend: While S(j)<=S(i): j = j + 1: Wend: Swap S(i), S(j)
If i <> 2 Then
For l = 1 To (i-1)/2: Swap S(l), S(i-l): Next l
End If
Фиксация(y)
Next y
End Sub
Sub Фиксация(k As Integer)
Dim i As Integer, var As String
var = "Перестановка " & Str(k) & ":": For i = 1 To n: var = var & " " & Str(S(i)): Next i: MsgBox var
End Sub
Sub Swap(ByRef x As Integer, ByRef y As Integer) 'Обмен значениями
Dim m As Integer
m = x: x = y: y = m
End Sub

Dim S() As Integer, Q() As Integer, P() As Integer
Const n As Integer = 7 'Количество пунктов
Sub Генератор_перестановок() 'Отладочный вариант
Dim i As Integer, j As Integer, z As Integer, y As Integer, l As Integer, b As Integer, d As Integer, h As Integer
ReDim S(1 To n, 1 To n), Q(1 To 30, 1 To n), P(1 To n)
S(1,1)=0: S(1,2)=5: S(1,3)=9: S(1,4)=6: S(1,5)=3: S(1,6)=5: S(1,7)=9: S(2,1)=8: S(2,2)=0: S(2,3)=8: S(2,4)=8
S(2,5)=5: S(2,6)=9: S(2,7)=2: S(3,1)=6: S(3,2)=9: S(3,3)=0: S(3,4)=1: S(3,5)=6: S(3,6)=7: S(3,7)=3
S(4,1)=7: S(4,2)=11: S(4,3)=4: S(4,4)=0: S(4,5)=4: S(4,6)=2: S(4,7)=9: S(5,1)=4: S(5,2)=6: S(5,3)=3: S(5,4)=2
S(5,5)=0: S(5,6)=2: S(5,7)=8: S(6,1)=5: S(6,2)=2: S(6,3)=2: S(6,4)=8: S(6,5)=4: S(6,6)=0: S(6,7)=3
S(7,1)=8: S(7,2)=1: S(7,3)=3: S(7,4)=16: S(7,5)=5: S(7,6)=3: S(7,7)=0: b = 1000
For i = 1 To n: P(i) = n + 1 - i: Next i: z = 1: For i = 1 To n - 1: z = z * i: Next i
For y = 1 To z
If y <> 1 Then
i = 2: j = 1: While P(i-1)<=P(i): i = i + 1: Wend: While P(j)<=P(i): j = j + 1: Wend: Swap P(i), P(j)
If i <> 2 Then
For l = 1 To (i-1)/2: Swap P(l), P(i-l): Next l
End If
End If
d = S(P(n),P(1)): For l = 1 To n-1: d = d +S( P(l), P(l+1)): Next l
If d <= b Then
If d < b Then h = 1: b = d: For l = 1 To n: Q(h,l) = P(l): Next l: h = h + 1: Фиксация h b
End If
Next y
End Sub
Sub Фиксация(k As Integer, d As Integer)
Dim i As Integer, var As String
var = "Маршрут " & Str(k) & ":": For i = 1 To n: var = var & " " & Str(P(i)): Next i
var = var & ". Длина: " & Str(d): MsgBox var
End Sub
Sub Swap(ByRef x As Integer, ByRef y As Integer) 'Обмен значениями
Dim m As Integer
m = x: x = y: y = m
End Sub

13 EMBED Equation.3 1415









MsgBox "Error encountered while trying to open file," _
& vbCrLf &S "please retry.", vbExclamation, "Text Editor"

Private Sub Form_Click()
Dim SFont, PFont
For SFont = 1 to Screen.FontCount
For PFont = 1 to Printer.FontCount
If Screen.Fonts(Sfont) = Printer.Fonts(Pfont) Then
Debug.Print Printer.Fonts(Pfont)
Exit For ' Выход из внутреннего цикла
End If
Next PFont
Next SFont
End Sub

For <переменная цикла> = <начальное значение> To <конечное значение> [Step <приращение>]
[<блок операторов>]
[Exit For]
[<блок операторов>]
Next [<счетчик>[, < счетчик >] [,...]]
Do [{While | Until} <условие>]
[<блок операторов>]
[Exit Do]
[<блок операторов>]
Loop

Private Sub Form_Click()
Dim SFont, PFont
For SFont = 1 to Screen.FontCount
For PFont = 1 to Printer.FontCount
If Screen.Fonts(Sfont) = Printer.Fonts(Pfont) Then
Debug.Print Printer.Fonts(Pfont)
End If
Next PFont
Next SFont
End Sub

Sub ListTableDefsO
Dim objDb As Database
Dim MyTableDef as TableDef
Set objDb = OpenDatabase("c:\vb\biblio.mdb", True, False)
For Each MyTableDef In objDb.TableDefs ()
Listl.AddItem MyTableDef.Name
Next MyTableDef
End Sub

For Each <Элемент> In <Группа>
<операторы>
Next Элемент

Private Sub Form_Click ()
Dim I As Integer
For i = 0 To Screen.FontCount
Debug.Print Screen.Fonts(i)
Next
End Sub

For <переменная цикла> = <начальное значение> To <конечное значение> [Step <шаг изменения>]
<блок операторов>
Next [переменная цикла]

Do
<блок операторов>
Loop Until <условие>

Do Until <условие>
<блок операторов>
Loop

Do
<блок операторов>
Loop While <условие>

ДлиннаяСтрока – текстовая переменная с исходной строкой
Подстрока – искомая в ДлиннаяСтрока подстрока
Dim позиция, счетчик
позиция = 1
Do While InStr(позиция, ДлиннаяСтрока, Подстрока)
позиция = InStr(позиция, ДлиннаяСтрока, Подстрока) + 1
счетчик = счетчик + 1
Loop
КолПодстрок = счетчик

Do while <условие>
<блок операторов>
Loop

Private Sub mnuCut_Click (Index As Integer)
Select Case Index
Case 0 'Команда Cut.
CopyActiveControl 'Вызовы общих процедур.
ClearActiveControl
Case 1 'Команда Copy.
CopyActiveControl
Case 2 'Команда Clear.
ClearActiveControl
Case 3 'Команда Paste.
PasteActiveControl
Case Else
frmFind.Show 'Показать диалоговое окно Find.
End Select
End Sub

Select Case <проверяемое выражение>
[Case <список значений 1>
[<1-ый блок операторов>]]
[Case < список значений 2>
[<2-ой блок операторов >]]
...
[Case Else
[]]
End Select

Private Sub mnuCut_Click (Index As Integer)
If Index = 0 Then 'Команда Cut
CopyActiveControl 'Вызовы общих процедур
ClearActiveControl Elself Index = 1 Then 'Команда Copy
CopyActiveControl
ElseIf Index = 2 Then 'Команда Clear
ClearActiveControl
Else 'Команда Paste
PasteActiveControl
End If
End Sub

If <условие 1> Then
[<блок операторов 1>]
[ElseIf < условие 2> Then
[блок операторов 2]] ...
[Else
[<блок операторов n>]]
End If

If anyDate < Now Then
anyDate = Now
Timer1.Enabled = False ' Запретить таймер.
End If

If <условие> Then <один оператор>

If <условие> Then
<блок операторов>
End If


13 EMBED MSPhotoEd.3 1415 Структура проекта VCR в Object Browser

13 EMBED MSPhotoEd.3 1415 Главная форма приложения VCR.







Приложенные файлы

  • doc 8820694
    Размер файла: 2 MB Загрузок: 0

Добавить комментарий