Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Главный параметр сложности алгоритмаСтр 1 из 4Следующая ⇒
Технологии программирования Содержание лекции:
1) Свойства алгоритма; 2) Сложность алгоритма. O- и ϴ - нотации; 3) Исполнитель алгоритма; 4) Инварианты. Индуктивные функции; 5) Абстракции. Интерфейс абстракции; 6) Рекурсия. Принцип разделяй и властвуй; 7) Основная теорема о рекурсии; 8) Быстрое вычисление степеней.
Свойства алгоритма Исполнитель
Алгоритм – это последовательность команд для исполнителя, обладающая рядом свойств: 1) полезность, т.е. умение решать поставленную задачу; 2) детерминированность, т.е. каждый шаг алгоритма должен быть строго определён во всех возможных ситуациях; 3) конечность, т.е. способность алгоритма завершиться для любого множества входных данных; 4) массовость, т.е. применимость алгоритма к разнообразным входным данным.
Алгоритм для своего исполнения требует от исполнителя некоторых ресурсов.
Программа – это запись алгоритма на формальном языке.
Исполнители Одна задача – несколько алгоритмов – разные используемые ресурсы.
Разные исполнители – разные элементарные действия и элементарные объекты.
Исполнитель “компьютер”: 1) устройство центральный процессор; 2) элементарные действия – сложение, умножение, сравнение, переход и т.д. 3) устройство память как хранитель элементарных объектов; 4) элементарные объекты – целые, вещественные числа.
Эффективность – способность алгоритма использовать ограниченное количество ресурсов.
Сложность алгоритма. O- и ϴ - нотации Сложность алгоритма Какая бывает сложность алгоритма: 1) комбинационная сложность – минимальное число элементов для реализации алгоритма в виде вычислительного устройства; 2) описательная сложность – длина описания алгоритма на формальном языке; 3) вычислительная сложность – количество элементарных операций, исполняемых алгоритмом для неких входных данных.
Нет циклов – описательная сложность примерно коррелирует с вычислительной.
Есть циклы – интересна асимптотика зависимости времени вычисления от входных данных.
Главный параметр сложности алгоритма
Введём понятие главный параметр N, наиболее сильно влияющий на скорость исполнения алгоритма. Это может быть: 1) размер массива; 2) количество символов в строке; 3) количество битов в записи числа; 4) если таких параметров несколько – обобщённый параметр, функция от нескольких параметров.
Нотация сложности. Символ ϴ (читается " тэта большое" ) Далее: сложность ≡ – вычислительная сложность. Функция f(N) имеет порядок ϴ (g(N)), если существуют постоянные c1, c2 и N1 такие, что для всех N> N1. 0 ≤ c1g(N) ≤ f (N) ≤ c2g(N) ϴ (f(n)) – класс функций, примерно пропорциональных f(n).
Нотация сложности. Символ O (читается " О большое" ) Функция f(N) имеет порядок O(g(N)), если существуют постоянные c1 и N1 такие, что для всех N> N1. f(N) ≤ c1g(N) O(f(n)) – класс функций, ограниченных сверху cf(n).
Приближённое вычисление сложности
Пусть F(N) – функция сложности алгоритма в зависимости от N. Тогда если существует такая функция G(N) (асимптотическая функция) и константа C, что то сложность алгоритма F(N) определяется функцией G(N) с коэффициентом амортизации C.
Асимптотика основных зависимостей
Класс сложности определяется по асимптотической зависимости F(N).
Экспонента с любым коэффициентом превосходит любую степень.
Степень с любым коэффициентом, большим единицы, превосходит логарифм по любому основанию, большему единицы.
Логарифм по любому основанию, большему единицы превосходит 1.
F(N) = N3 + 7N2 - 14N = ϴ (N3)
F(N) = 1.01N + N10 = ϴ (1.01N)
F(N) = N1.3 + 10log2N = ϴ (N1.3)
На практике чаще используют O-нотацию, так как ϴ -нотацию обычно сложнее доказывать.
Зависимость времени исполнения от исходных данных
Пусть имеется массив A длиной N элементов. Сколько операций потребуется, чтобы обнаружить номер первого вхождения элемента со значением P алгоритмом, заключающимся в последовательном просмотре элементов массива?
Kmin = 1
Kmax = N
Подходит ли символ ϴ?
Нет. Для данного алгоритма подходит O-символ: f(N) = O(N).
Пусть имеется массив A длиной N элементов. Сколько операций потребуется, чтобы сложить все элементы массива?
K = N
Подходит ли символ ϴ?
Подходит. f(N) = ϴ (N).
Задача о рюкзаке
Обратим внимание на то, что предметы разрезать на куски нельзя. Если это разрешить, то задача будет иметь простое решение.
Для решения задачи достаточно перебрать все возможные комбинации из N предметов. Это гарантирует то, что мы не пропустим нужной комбинации.
Для определения количества комбинаций можно рассуждать так, что K предметов можно выбрать из N предметов (CNK), и так для всех K от 0 до N.
F(N) = (1 + 1) N = 2N
Свойства алгоритма
Предложенный алгоритм: 1) детерминированный; 2) конечный; 3) массовый; 4) полезный. Его сложность пропорциональна 2N, так как требуется перебрать все возможные комбинации предметов.
NP-задачи о рюкзаке
Задача о рюкзаке относится к классу NP-полных. Быстрое (полиномиальное) точное решение таких задач (пока) не найдено. Если будет найдено решение одной из NP-полных задач, то будут решены все задачи из этого класса. Сейчас их решают приближённо.
Исполнитель алгоритма Исполнители
Нашим исполнителем будет язык C++.
Элементарные типы отображаются на вычислительную систему char, int, double.
Элементарные операции аппаратного исполнителя: операции над элементарными типами и операции передачи управления.
Типы данных языка – комбинация элементарных типов данных.
Операции языка – комбинация элементарных операций.
Представление типов
Целые числа – двоичное представление.
Простые элементарные операции: сложение, вычитание, присваивание и т.д.
Сложные элементарные операции: целочисленное умножение, деление (не на степень двойки), переход.
Приведём пример кода: if (x > 0) t = 1; else t = 0; Этот код выполнится выполняется намного медленнее, чем t = x > 0; (потому что для t = x > 0; есть машинная команда).
Инварианты. Индуктивные функции Понятие абстракции
Как только появляются объекты, появляются абстракции – механизм разделения сложных объектов на более простые, без деталировки подробностей разделения.
Функциональная абстракция – разделение функций, методов, которые манипулируют с объектами, с их реализацией.
Интерфейс абстракции – набор методов, характерных для данной абстракции.
Пример: абстракция массива
1) create – создать массив (статический или динамический). int a[100]; // статический int *b = calloc(100, sizeof(int)); // динамический int *c = new int[100]; // динамический 2) destroy – удалить массив (статический или динамический). free(b); delete c; // можно и delete [] c 3) fetch – обратиться к элементу массива. int q1 = a[i]; int q2 = b[i]; int q3 = c[i];
Для массива основная операция – это доступ к элементу. Она выглядит одинаково для всех представлений.
Абстракция “стек”
Одна из удобных абстракций – стек.
Стек должен предоставлять нам методы: 1) create – создание стека (может быть, потребуется аргумент, определяющий максимальный размер стека); 2) push – занесение элемента в стек (размер стека увеличивается на единицу, занесённый элемент становится вершиной стека); 3) pop – извлечь элемент, являющийся вершиной стека и уменьшить размер стека на единицу (если стек пуст, то значение операции не определено); 4) peek – получить значение элемента, находящегося на вершине стека, не изменяя стека (если стек пуст, значение операции не определено); 5) empty – предикат истинен, когда стек пуст; 6) destroy – уничтожить стек.
Абстракция “множество”
Множество – это совокупность однотипных элементов, на которых определена операция сравнения.
Множество обозначается списком значений внутри фигурных скобок.
Пустое множество: s = {}.
Множество должно предоставлять нам методы:
1) insert – добавление элемента в множество. {1, 2, 3}.insert(5) -> {1, 2, 3, 5} {1, 2, 3}.insert{2} -> {1, 2, 3} 2) remove – удалить элемент из множества. {1, 2, 3}.remove(3) -> {1, 2} {1, 2, 3}.remove(5) -> не определено. 3) in – определить принадлежность множеству. {1, 2, 3}.in(2) -> true {1, 2, 3}.in(5) -> false 4) size – определить количество элементов в множестве.
Рекуррентность и рекурсия
Рекуррентная форма -> рекурсивный алгоритм. int fibo(int n) { if (n == 0) return 0; if (n == 1) return 1; return fibo(n-1) + fibo(n-2); }
Три вопроса: 1) корректен ли он? 2) как оценить время его работы? 3) как его ускорить?
Дерево вызовов функции для n = 5
Как ускорить?
Проблема в том, что мы много раз повторно вычисляем значение функции от одних и тех же аргументов.
Третий вопрос: можно ли ускорить алгоритм?
Вводим добавочный массив.
int fibo(int n) { const int MAXN = 1000; static int c[MAXN]; if (n == 0) return 0; if (n == 1) return 1; if (c[n] > 0) return c[n]; return c[n] = fibo(n-1) + fibo(n-2); }
Дерево вызовов модифицированной функции для n = 5
Как умножать длинные числа?
Школьный алгоритм: O(n2)
Алгоритм быстрого умножения
Можно ли быстрее?
Да. Используя принцип разделяй и властвуй.
Быстрый алгоритм умножения был изобретён Гауссом в 19 веке и переизобретён Анатолием Карацубой в 1960-м году.
Разделим число (n) на две примерно равные половины: N1 = Tx1 + y1 N2 = Tx2 + y2
При умножении в столбик N1 × N2 = T2x1x2 + T (x1y2 + x2y1) + y1y2
Это – четыре операции умножения и три операции сложения.
Число T определяет, сколько нулей нужно добавить к концу числа в соответствующей системе счисления.
Алгоритм Карацубы
Алгоритм Карацубы находит произведение по другой формуле:
N1 × N2 = T2x1x2 + T (x1 + y1)(x2 + y2) - x1x2 - y1y2) + y1y2 N1 = 56, N2 = 78, T = 10 x1 = 5, y1 = 6 x2 = 7, y2 = 8 x1x2 = 5 × 7 = 35 (x1 + y1) (x2 + y2) = (5 + 6) (7 + 8) = 11 ∗ 15 = 165 y1y2 = 6 × 8 = 48 N1 × N2 = 35 ∗ 100 + (165 - 35 - 48) ∗ 10 + 48 = 4368
Т.е. 3 операции умножения и 6 сложения.
Основная теорема о рекурсии Основная теорема о рекурсии
Пусть для некоторых a > 0, b > 1, d ≥ 0. Тогда
Ещё о сложности Введём вектор-столбец , состоящий их двух элементов последовательности Фибоначчи, и умножим его справа на матрицу :
Для вектора-столбца из элементов Fn-1 и Fn умножение на ту же матрицу даст:
Таким образом,
Возведение в степень
Для нахождения n-го числа Фибоначчи достаточно вычислить
Можно ли возвести число в n-ую степень за число операций, меньших n - 1?
Быстрое вычисление степеней
Возведение в квадрат – это умножение на себя.
х16 = (х8)2 = ((х4)2)2 = (((х2)2)2)2
х18 = (х9)2 = ((х8 * х)2)2 = (((х2)2)2 * х)2
Рекуррентная формула
Технологии программирования Содержание лекции:
1) Свойства алгоритма; 2) Сложность алгоритма. O- и ϴ - нотации; 3) Исполнитель алгоритма; 4) Инварианты. Индуктивные функции; 5) Абстракции. Интерфейс абстракции; 6) Рекурсия. Принцип разделяй и властвуй; 7) Основная теорема о рекурсии; 8) Быстрое вычисление степеней.
Свойства алгоритма Исполнитель
Алгоритм – это последовательность команд для исполнителя, обладающая рядом свойств: 1) полезность, т.е. умение решать поставленную задачу; 2) детерминированность, т.е. каждый шаг алгоритма должен быть строго определён во всех возможных ситуациях; 3) конечность, т.е. способность алгоритма завершиться для любого множества входных данных; 4) массовость, т.е. применимость алгоритма к разнообразным входным данным.
Алгоритм для своего исполнения требует от исполнителя некоторых ресурсов.
Программа – это запись алгоритма на формальном языке.
Исполнители Одна задача – несколько алгоритмов – разные используемые ресурсы.
Разные исполнители – разные элементарные действия и элементарные объекты.
Исполнитель “компьютер”: 1) устройство центральный процессор; 2) элементарные действия – сложение, умножение, сравнение, переход и т.д. 3) устройство память как хранитель элементарных объектов; 4) элементарные объекты – целые, вещественные числа.
Эффективность – способность алгоритма использовать ограниченное количество ресурсов.
Сложность алгоритма. O- и ϴ - нотации Сложность алгоритма Какая бывает сложность алгоритма: 1) комбинационная сложность – минимальное число элементов для реализации алгоритма в виде вычислительного устройства; 2) описательная сложность – длина описания алгоритма на формальном языке; 3) вычислительная сложность – количество элементарных операций, исполняемых алгоритмом для неких входных данных.
Нет циклов – описательная сложность примерно коррелирует с вычислительной.
Есть циклы – интересна асимптотика зависимости времени вычисления от входных данных.
Главный параметр сложности алгоритма
Введём понятие главный параметр N, наиболее сильно влияющий на скорость исполнения алгоритма. Это может быть: 1) размер массива; 2) количество символов в строке; 3) количество битов в записи числа; 4) если таких параметров несколько – обобщённый параметр, функция от нескольких параметров.
Нотация сложности. Символ ϴ (читается " тэта большое" ) Далее: сложность ≡ – вычислительная сложность. Функция f(N) имеет порядок ϴ (g(N)), если существуют постоянные c1, c2 и N1 такие, что для всех N> N1. 0 ≤ c1g(N) ≤ f (N) ≤ c2g(N) ϴ (f(n)) – класс функций, примерно пропорциональных f(n).
Нотация сложности. Символ O (читается " О большое" ) Функция f(N) имеет порядок O(g(N)), если существуют постоянные c1 и N1 такие, что для всех N> N1. f(N) ≤ c1g(N) O(f(n)) – класс функций, ограниченных сверху cf(n).
|
Последнее изменение этой страницы: 2017-03-17; Просмотров: 1104; Нарушение авторского права страницы