
- •Министерство образования и науки Российской Федерации
- •Цель лекции
- •План лекции
- •1 Происхождение вычислительных машин
- •2 Изучение алгоритмов
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Биты и их хранение
- •2 Оперативная память
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Устройства внешней памяти
- •3 Хранение и поиск файлов
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Представление числовых значений
- •2 Хранение целых чисел
- •3 Хранение дробей
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Представление текста
- •2 Представление изображений
- •Достоинства пиксельной графики
- •Недостатки пиксельной графики
- •Достоинства векторной графики
- •Недостатки векторной графики
- •3 Представление звука
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Сжатие изображений
- •2 Ошибки передачи данных
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Архитектура эвм
- •2 Связь процессора с другими устройствами
- •3 Другие архитектуры
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Машинный язык
- •2 Пример машинного языка
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Выполнение программы
- •2 Пример выполнения программы
- •3 Программы и данные
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Логические операции
- •2 Операции сдвига
- •3 Арифметические операции
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Эволюция операционных систем
- •2 Архитектура операционных систем
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Понятие процесса
- •2 Управление процессами
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Классификация сетей
- •2 Сетевые протоколы*
- •3 Безопасность сетей
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Понятие алгоритма
- •2 Представление алгоритма
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Теория решения задач
- •2 Общие методы решения задач
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Алгоритм последовательного поиска
- •2 Управление циклами
- •3 Алгоритм сортировки методом вставки
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Алгоритмы поиска и сортировки
- •2 Управление рекурсией
- •3 Разработка рекурсивных процедур
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Эффективность алгоритмов
- •2 Верификация программ
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Эволюция и классификация языков программирования
- •2 Концепции традиционного программирования
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Процедурные единицы
- •2 Реализация языка программирования
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Объектно-ориентированное программирование
- •2 Декларативное программирование
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Структуры данных
- •Integer Scores (2.9).
- •2 Статические и динамические структуры
- •3 Указатели
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Массивы
- •2 Списки
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Структура и функции стека
- •2 Реализация стека
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Очереди
- •2 Деревья
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Пользовательские типы данных
- •Int Age;
- •2 Классы
- •Int *StackEntries;
- •3 Стандартная библиотека шаблонов
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Роль операционной системы
- •2 Последовательные файлы
- •3 Вопросы программирования
- •0000000010000110
- •001100010011001100110100
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Основные положения индексации
- •2 Вопросы программирования
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Основные положения хеширования
- •2 Вопросы программирования
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Общие вопросы
- •2 Система управления базой данных
- •3 Поддержка целостности баз данных
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Модели баз данных
- •2 Реляционная модель баз данных
- •3 Объектно-ориентированные базы данных
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Интеллект и машины
- •2 Распознавание образов
- •3 Мышление
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Искусственные нейронные сети
- •2 Генетические алгоритмы
- •Контрольные вопросы
- •Невычислимые функции Цель лекции
- •План лекции
- •1 Основы машины Тьюринга
- •2 Невычислимая функция
- •3 Сложность задач
- •Листинг 1. Процедура MergeLists для объединения двух упорядоченных списков
- •Листинг 2. Алгоритм сортировки слиянием, реализованный в процедуре MergeSort
- •Контрольные вопросы
- •Цель лекции
- •План лекции
- •1 Шифрование с открытым ключом
- •2 Модульная арифметика
- •Контрольные вопросы
- •Литература
- •Internet-ресурсы
3 Сложность задач
Мы начнем с возвращения к изучению эффективности алгоритмов, начатому ранее. Там мы применяли Θ-представление (большая тэтапредставление) для классификации алгоритмов в зависимости от времени их выполнения. Мы узнали, что алгоритм сортировки вставкой принадлежит классу Θ(n2), алгоритм последовательного поиска — классу Θ(n), а алгоритм бинарного поиска — классу Θ(lgn). Теперь эта классификационная система поможет нам вычислять сложность задач. Наша Цель лекции — разработать классификационную систему, при помощи которой можно будет определить, какие проблемы являются более сложными, чем другие, и, в итоге, какие проблемы настолько сложны, что их решение невозможно в практическом смысле.
Причина того, что мы базируем наше текущее исследование на знании эффективности алгоритмов, состоит в том, что мы хотим измерить сложность проблем в терминах сложности их решений. Мы считаем задачу простой, если ее решение просто; сложная задача — это задача, для которой нет простого решения. Обратите внимание: тот факт, что решение задачи является сложным, не означает, что сама проблема сложна. Действительно, у задачи может быть несколько решений, и одно из них просто обязано быть сложным. Следовательно, чтобы утверждать, что проблема сложна, необходимо показать, что ни одно из ее решений не является простым.
Предметом вычислительной техники являются задачи, которые умеют решать машины. Решения этих задач формулируются в виде алгоритмов. Таким образом, сложность проблемы определяется свойствами алгоритмов, решающих ее. Точнее, сложность простейшего алгоритма для решения задачи считается сложностью этой задачи.
Но как же измерить сложность алгоритма? К сожалению, термин «сложность» можно интерпретировать по-разному. Например, можно рассматривать количество принятых решений и ветвлений алгоритма. С этой точки зрения сложный алгоритм должен иметь разветвленный, переплетенный набор указаний. Эта интерпретация может быть удобна разработчику программного обеспечения, которого интересуют вопросы разработки и представления алгоритма, но не вопрос сложности с точки зрения машины. При выборе очередной инструкции для выполнения машина на самом деле не принимает решения, просто выполняет машинный цикл снова и снова, каждый раз выполняя команду, на которую указывает счетчик команд. Следовательно, машина выполняет набор сложных инструкций как простой последовательный список команд. То есть в этом случае измеряются, скорее, трудности, возникающие при создании алгоритмов, а не сложность самих алгоритмов.
Интерпретацию, которая более точно отражает сложность алгоритма, можно получить, рассматривая алгоритмы с точки зрения машины. В этом контексте мы измеряем сложность алгоритма в терминах времени, необходимого для его выполнения, которое пропорционально количеству требуемых действий. Обратите внимание, что это количество не совпадает с числом команд в написанной программе. Цикл, тело которого состоит из одного оператора печати, но который должен выполниться 100 раз, во время выполнения эквивалентен 100 операторам печати. Следовательно, такая процедура считается более сложной, чем список из 50 отдельно написанных операторов печати, хотя этот список выглядит длиннее в тексте программы. Дело в том, что значение сложности в конечном итоге определяется временем, которое требуется машине для выполнения алгоритма, а не размером программы, представляющей решение.
Таким образом, мы считаем задачу сложной, если для ее решения требуется много времени. Это определение сложности называется временной сложностью (time complexity). Действительно, изучение эффективности алгоритмов выливается в изучение их временной сложности — это всего лишь две стороны одной медали. То есть «более эффективный» алгоритм равен «менее сложному». Так, в терминах временной сложности, алгоритм последовательного поиска (эффективность которого равна Θ(n)) является более сложным решением задачи поиска в списке, чем алгоритм бинарного поиска (чья эффективность равна Θ(lg n)).
Применим наши знания сложности алгоритмов в поиске способов определения сложности задач. Мы считаем, что (временная) сложность задачи равна Θ(f(n)), где f(n) — это некоторая математическая функция от n, если существует алгоритм решения этой задачи, временная сложность которого равна Θ(f(n)), и не существует других алгоритмов решения с меньшей временной сложностью. То есть (временная) сложность задачи определяется как (временная) сложность ее наилучшего решения. К сожалению, поиск лучшего решения задачи и доказательство, что оно действительно лучшее, — это зачастую сложная проблема сама по себе. В таких ситуациях для обозначения того, что нам известно о сложности задачи, применяется О-представление (вариант Θ-представления). Точнее, если f(n) — это математическая зависимость от n и если задачу можно решить алгоритмом класса Θ(f(n)), то мы говорим, что это задача класса О(f(n)). То есть говоря, что задача принадлежит О(f(n)), мы имеем в виду, что для нее есть решение со сложностью Θ(f(n)), но, возможно, существуют и более хорошие решения.
Альтернативой измерению сложности в терминах времени является изменение пространственных требований — такое измерение известно под названием пространственной сложности (space complexity). Пространственная сложность задачи определяется количеством машинной памяти, необходимой для решения задачи. В этой главе мы узнали, что временная сложность сортировки списка из п записей равна О(n lg n). Пространственная сложность той же задачи не превышает О(n + 1) = О(n). Действительно, для сортировки списка из п записей методом вставки необходимо пространство для хранения самого списка и еще одной временной записи. Таким образом, если нам потребуется сортировка все более длинных списков, мы увидим, что время, требуемое для выполнения каждой задачи, будет увеличиваться быстрее, чем расходуемое пространство. Это достаточно распространенный феномен. Так как использование пространства требует времени, пространственная сложность задачи никогда не будет увеличиваться быстрее, чем ее временная сложность.
Часто между временной и пространственной сложностью ищутся какие-либо компромиссы. В некоторых приложениях удобнее выполнять определенные вычисления заранее и хранить результаты в таблице, из которой при необходимости их легко восстановить. Такая техника табличного поиска сокращает время, необходимое конечной системе, за счет дополнительного пространства, которое занимает таблица. С другой стороны, сжатие данных зачастую применяется для сокращения требований к пространству, но при этом необходимо дополнительное время для сжатия и восстановления данных.
Наши исследования процессов поиска и сортировки приводят к выводу, что задача поиска в списке длиной п (когда все, что мы знаем о списке — что он был предварительно упорядочен) принадлежит O(lg n), так как эту задачу может решить бинарный поиск. Кроме того, исследователи показали, что проблема поиска в действительности принадлежит Θ(lg n), то есть бинарный поиск является оптимальным решением задачи. С другой стороны, мы знаем, что задача сортировки списка длиной п (когда мы ничего не знаем об исходном распределении значений в списке) принадлежит О(n2), потому что алгоритм сортировки вставкой может решить эту задачу. Однако, как показали исследования, задача сортировки принадлежит Q(n lg n), то есть алгоритм сортировки вставкой — это не оптимальное решение (в смысле временной сложности).
Примером лучшего решения является алгоритм сортировки слиянием. Он состоит в объединении небольших отсортированных частей списка для получения более крупных отсортированных фрагментов, которые объединяются в еще более длинные отсортированные отрезки списка. Каждый процесс слияния выполняется при помощи алгоритма слияния, который мы рассмотрели при обсуждении последовательных файлов.. Полный (рекурсивный) алгоритм сортировки слиянием представлен в виде процедуры MergeSort (листинг 1). Когда эта процедура получает список для сортировки, сначала она проверяет, содержится ли в списке более одной записи. Если нет, то задача процедуры выполнена. Если записей больше одной, процедура делит список на две части, которые отправляет для сортировки другим копиям процедуры MergeSort, а затем объединяет отсортированные части для получения конечного отсортированного варианта списка.