- •Передачу параметров в функцию по значению, а не по ссылке (при этом передача по ссылке эмулируется с помощью указателей);
- •Области действия имён; (область видимости переменной).
- •Достоинства:
- •Представление целых чисел в эвм
- •Основные типы данных, операции над ними.
- •Операции
- •Преобразование типов
- •Особенности операций для вещественных чисел
- •3.1. Операторы и блоки.
- •3.2. Оператор if – else
- •3.3. Конструкция else-if.
- •3.4. Оператор switch
- •3.5. Циклы while и for
- •3.6. Цикл do-while
- •3.7. Операторы break и continue
- •3.8. Оператор goto и метки
- •3.9. Оператор return
- •Инвариант
- •Указатели
- •Массивы
- •Связь между указателями и массивами
- •Представление в эвм
- •Создание указателя на массив
- •Инициализация массивов
- •Операции над указателями
- •Замечание! 2 указателя нельзя суммировать, но можно прибавлять константу. Сравнивать допустимо только с указателями того же типа или с null
- •Метод барьера в линейном поиске
- •Метод барьера при быстрой сортировке массива
- •Сортировка методом вставки. В отсортированной части массива последний элемент – барьер.
- •Процедуры
- •Локальные и глобальные переменные
- •Локальные переменные
- •Глобальные переменные
- •Средний и наихудший случай
- •Дополнительно (то же самое)
- •Анализ эффективности алгоритмов не должен зависеть от:
- •Временная сложность алгоритма
- •Некоторые свойства временной сложности алгоритма (функции f(n) )
- •Характеристики рекурсии
- •Виды рекурсии
- •Когда не нужно применять рекурсию
- •Применение эвристик.
- •Метод ветвей и границ (доп. Из Wikipedia)
- •Алгоритм Неймана.
- •Линейный конгруэнтный метод
- •Выбор параметров, выбор модуля и множителя.
- •Сдвиг на несколько символов: Если не совпадает , то сдвигаем образ вправо до последнего его стоп-символа. Если «стоп-символа» вообще нет в образе, то образ смещается за этот символ.
- •Вопросы на экзамен по информатике:
- •Перевести отрицательное целое число (он любое может назвать) в дополнительный код.
- •Есть ли смысл применять метод барьера в поиске подстроки в строке?
- •Задачи на экзамене:
- •Задача о Ханойских башнях
- •Бинарный поиск элемента в массиве
- •Сумма цифр в числе
- •Число различных элементов в символьном массиве
- •Сгенерировать все перестановки в целочисленном массиве (Билет 1).
- •Функция, возвращающая I и j такие, чтобы сумма эл-тов в I-ой строке равнялась сумме в j-ом столбце.
- •Есть одномерный массив целых чисел и нужно построить функцию, получающую на вход вещественное число X и возвращающую индекс элемента, который ближе всего к этому числу.
- •Функция strcpy (char *s1, char *s2) , билет 12.
- •Реализация strcat(); Билет 7.
- •Билет 5. Функция, выдаёт частное и остаток от деления X на y, нельзя пользоваться / и % .
- •Метод генерации случайной перестановки ( Тасование Фишера-Йетса).(не ок)
Дополнительно (то же самое)
При анализе эффективности одинаково важны как время выполнения алгоритма, так и занимаемая им память.
Анализ эффективности алгоритмов не должен зависеть от:
От их реализации, поскольку они очень сильно зависят от стиля программирования и не позволяют определить, какой из алгоритмов эффективнее.
От особенностей конкретного компьютера.
От выбора конкретных данных.
Чтобы преодолеть эти трудности, были разработаны математические методы анализа алгоритмов.
Оценка эффективности алгоритма
Быстродействие алгоритма связано с количеством выполняемых операций, поэтому оценить его эффективность можно путем их простого подсчета. Время выполнения алгоритма выражается функцией, зависящей от размера задачи.
Пример: вложенные циклы.
Что конкретно нужно знать о быстродействии алгоритма? Важнее всего знать, насколько быстро возрастает время его выполнения с увеличением размера задачи:
Время выполнения алгоритма А прямо пропорционально n2.
Время выполнения алгоритма В прямо пропорционально n.
По этим утверждениям нельзя определить, сколько именно времени выполняется алгоритм А или В. Главное, что при решении больших задач алгоритм В работает намного быстрее.
Временная сложность алгоритма
Допустим, выполняется следующее утверждение: время выполнения алгоритма А прямо пропорционально функции f(n). В таких случаях говорят, что алгоритм А имеет порядок f(n), обозначающийся как O(f(n)). Функция f(n) называется временной сложностью алгоритма.
Некоторые свойства временной сложности алгоритма (функции f(n) )
При оценке сложности алгоритма можно учитывать только старшую степень. Например, если алгоритм имеет сложность O(n3 + 4*n2 + 3*n), он имеет порядок O(n3).
При оценке сложности алгоритма можно игнорировать множитель при старшей степени.
Функции, описывающие сложность алгоритма, можно складывать. Например, если алгоритм имеет сложность О(n2) +О(n), то говорят, что он имеет сложность О(n2+n).
При оценке эффективности алгоритма нужно оценить лишь порядок его сложности.
Наихудший и средний варианты
При решении конкретных задач одинаковой размерности время выполнения алгоритма может оказаться разным. Например, время, необходимое для поиска n элементов, может зависеть от природы самих элементов. Обычно оценивается максимальное. Но следует иметь в виду, что наихудший вариант на практике встречается редко.
Анализ среднего варианта позволяет оценить среднее время выполнения алгоритма при решении задачи размера n. Как правило, анализ среднего варианта выполнить намного сложнее, чем анализ наихудшего варианта. Одна из трудностей заключается в определении вероятностей появления разных задач одинаковой размерности. Вторая трудность заключается в вычислении распределений разных значений. Анализ наихудшего варианта легче поддается вычислениям и поэтому выполняется намного чаще.
Замечание! Фактически при анализе сложности алгоритма неявно предполагается, что он будет применяться для решения больших задач.
Замечание! Анализ сложности алгоритмов ориентируется на большие задачи. Если максимальный размер задачи невелик, время выполнения алгоритмов разной сложности не будет значительно отличаться. Если заранее известно, что размер задачи никогда не будет больше, анализ эффективности алгоритмов можно не проводить. В таких случаях следует выбрать наиболее простой алгоритм, запрограммировать его и протестировать.
Следует стремиться к равновесию между быстродействием алгоритма и объемом занимаемой им памяти.
Довольно часто при оценке эффективности алгоритмов нужно отыскать компромисс между быстродействием и занимаемым объемом памяти. Итак, стиль и эффективность алгоритма одинаково важны. Анализ сложности алгоритмов ориентируется на большие задачи.
Фактически при анализе сложности алгоритма неявно предполагается, что он будет применяться для решения больших задач. Сравнение эффективности алгоритмов должно быть сосредоточено на их существенных различиях. При анализе эффективности одинаково важны как время выполнения алгоритма, так и занимаемая им память.
Как сравнить быстродействие двух алгоритмов, решающих одну и ту же задачу? Для этого их можно запрограммировать и запустить обе программы. У этого подхода есть три существенных недостатка.
1. Как запрограммированы алгоритмы?
Допустим, алгоритм А1 выполняется быстрее, чем алгоритм А2. Это может быть связано с тем, что программа, реализующая алгоритм, просто лучше написана. Следовательно, сравнивая время выполнения программ, вы на самом деле сравниваете реализации алгоритмов, а не сами алгоритмы. Реализации алгоритмов сравнивать бессмысленно, поскольку они очень сильно зависят от стиля программирования и не позволяют определить, какой из алгоритмов эффективнее.
Билет 11. Рекурсия
Рекурсивный объект – объект, частично или полностью определенный через самого себя.
Мощь рекурсии заключается в возможности определить бесконечное множество объектов с помощью конечного утверждения. Можно привести задачу большей размерности к задаче меньшей размерности. Необходимое и достаточное средство для рекурсивной формулировки программы – рекурсивная функция (процедура). Пример – функция расчета факториала: int factr(int n)
{
if(n==1) return(1);
return( factr(n-1)*n); /* рекурсивный вызов */
}
Необходимое и достаточное условие существования рекурсии:
А(n)
{
A(n)
}
При каждой рекурсивной активации процедуры создается новый набор локальных переменных. Хотя у них те же имена, что и у переменных предыдущей активации, их значения другие и любая возможность конфликта устраняется правилом видимости идентификаторов – идентификаторы всегда ссылаются на набор переменных, созданных последними.
Общая схема рекурсии такова: void решить задачу (N) {
if (n==1) решение ( ); else {
подготовка решения ( ); решить задачу для (N-1): } }
Что происходит, когда функция F выполняет рекурсивный вызов? Прежде всего, запоминается текущее состояние программы, необходимое для продолжения вычислений, когда управление снова вернется к ней. Затем F с новыми значениями аргументов начинает выполняться заново как бы с новым экземпляром программы. При следующем рекурсивном вызове F всё повторяется и т.д. до тех пор, пока очередной вызов F не приводит к какому-либо тривиальному случаю, разрешаемому без рекурсивных вызовов. Далее, в порядке, обратном тому, в котором запоминалась серия вызовов, производятся возвраты управления. В практических приложениях важно убедиться, что максимальная глубина рекурсивных вызовов не только конечна, но и достаточно мала. В противном случае не избежать переполнения стека - специально организованного участка памяти, где запоминаются отдельные состояния программы-функции.
