Анализ сложности алгоритмов

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

  1. Присваивать значение переменной
  2. Находить значение конкретного элемента в массиве
  3. Сравнивать два значения
  4. Инкрементировать значение
  5. Основные арифметические операции (например, сложение и умножение)
  6. Ветвление в операторt if происходит мгновенно

Рассмотрим следующий код и подсчитаем необходимое процессору число тактов для получения результата

        
        M = A[0]
        for i in range(n):
            if (A[i] >= M):
            M = A[i]
        
        
Таблица 1: Специальные названия для функций
f(n) Название
\(1\) За константу
\(\log n\) Логарифмический
\(n\) Линейный
\(n\log n\) ? Log Linear
\(n^{2}\) Квадратичный
\(n^{3}\) Кубический
\(2^{n}\) Экcпоненциальный
        
        test = 0
        for i in range(n):
           for j in range(n):
              test = test + i * j
        
        

Варианты ответов:

1. \(O(2^{n})\)     2. \(O(n)\)     3. \(O(n^{2})\)     \[ 1. O(n)   2. O(n^2)   3. O(log(n))   4. O(n^3) \

Проверить себя:

Правильный ответ 2
        
        test = 0
        for i in range(n):
           test = test + 1
        
        for j in range(n):
           test = test - 1
        
        
        

Варианты ответов:

\[ 1. O(n)   2. O(n^2)   3. O(log(n))   4. O(n^3) \]

Проверить себя:

Правильный ответ
        
        i = n
        while i > 0:
           k = 2 + 2
           i = i // 2
        
        
        

Варианты ответов:

\[ 1. O(n)   2. O(n^2)   3. O(log(n))   4. O(n^3) \]

Проверить себя:

Правильный ответ

Итераторы

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

it = s.__iter__() 			# Получить итератор для объекта s
while 1:
    try:
        i = it.__next__() 	# Получить следующий элемент
    except StopIteration:
    break
    ...						# выполнить операции над i

Полиморфизм

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

В Питоне отсутствует перегрузка - т.е. возможность иметь в одном классе несколько методов с одинаковыми именами, но с различными списками входных параметров. Отсутствует - управление доступом.

Экземпляры класса создаются посредством обращения к имени класса, как к функции, которой передаются все необходимые аргументы.

По умолчанию все эземпляры классов являются хешируемыми. Но если будет реализован метод __eq__(), экзепляры перестают быть хешируемыми.

Декоратор - это функция, которая в качестве аргумента принимает функцию или метод и возвращает измененную(декорированную) версию.

Статические методы - это методы, которые не получают аргумент self(первый аргумент). Для статических методов используется декоратор staticmethod. Вместо статических методов лучше создавать функции модуля или методы класса.