diff --git "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" index 835c283b..11b891f7 100644 --- "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" +++ "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" @@ -1,14 +1,10 @@ """ Задание 1. - Для каждой из трех задач выполнить следующее: - 1) для каждой инструкции рядом в комментарии определите сложность этой инструкции 2) определите сложность алгоритма в целом - укажите сложность непосредственно в этом файле точки, где нужно поработать вам, отмечены знаком '!!!' - Примечание: Если у вас возникают сложности, постарайтесь подумать как можно решить задачу, а не писать "мы это не проходили)". @@ -22,49 +18,43 @@ ############################################################################################# def check_1(lst_obj): """Функция должна создать множество из списка. - Алгоритм 3: Создать множество из списка - - Сложность: !!!. + Сложность: O(len...). """ - lst_to_set = set(lst_obj) # !!! + lst_to_set = set(lst_obj) # O(len...) return lst_to_set ############################################################################################# def check_2(lst_obj): """Функция должная вернуть True, если все элементы списка различаются. - Алгоритм 1: Проходимся по списку и для каждого элемента проверяем, что такой элемент отстутствует в оставшихся справа элементах - - Сложность: !!!. + Сложность: O(n**2). """ - for j in range(len(lst_obj)): # !!! - if lst_obj[j] in lst_obj[j+1:]: # !!! - return False # !!! - return True # !!! + for j in range(len(lst_obj)): # O(n) + if lst_obj[j] in lst_obj[j+1:]: # O(n) + return False # O(1) + return True # O(1) ############################################################################################# def check_3(lst_obj): """Функция должная вернуть True, если все элементы списка различаются. - Алгоритм 2: Вначале выполним для списка сортировку, далее, сравниваем элементы попарно Если присутствуют дубли, они будут находиться рядом. - - Сложность: !!! + Сложность: O(nlogn) """ - lst_copy = list(lst_obj) # !!! - lst_copy.sort() # !!! - for i in range(len(lst_obj) - 1): # !!! - if lst_copy[i] == lst_copy[i+1]: # !!! - return False # !!! - return True # !!! + lst_copy = list(lst_obj) # O(1) + lst_copy.sort() # O(nlogn) + for i in range(len(lst_obj) - 1): # O(n) + if lst_copy[i] == lst_copy[i+1]: # O(1) + return False # O(1) + return True # O(1) ############################################################################################# diff --git "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" index 3a5eabbc..1300061a 100644 --- "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" +++ "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" @@ -1,15 +1,11 @@ """ Задание 2. - Реализуйте два алгоритма. - Первый, в виде функции, должен обеспечивать поиск минимального значения для списка. В основе алгоритма должно быть сравнение каждого числа со всеми другими элементами списка. Сложность такого алгоритма: O(n^2) - квадратичная. - Второй, в виде функции, должен обеспечивать поиск минимального значения для списка. Сложность такого алгоритма: O(n) - линейная. - Примечание: Построить список можно через генератор списка. Если у вас возникают сложности, постарайтесь подумать как можно решить задачу, @@ -17,3 +13,27 @@ Алгоритмизатор должен развивать мышление, а это прежде всего практика. А без столкновения со сложностями его не развить. """ + +list_of_numbers = [7, 3, 8, 1, 11, 2, 37, 23] + + +def find_min_number_first(input_list): + for item in input_list: + flag = True + for i in input_list: + if i < item: + flag = False + if flag: + return item + + +def find_min_number_second(input_list): + minimum = input_list[0] + for item in input_list[1:]: + if item < minimum: + minimum = item + return minimum + + +print(find_min_number_first(list_of_numbers)) +print(find_min_number_second(list_of_numbers)) diff --git "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" index e52aafcb..290550e6 100644 --- "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" +++ "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" @@ -1,11 +1,9 @@ """ Задание 3. - Для этой задачи: 1) придумайте 1-3 решения (желательно хотя бы два) 2) оцените сложность каждого решения в нотации О-большое 3) сделайте вывод, какое решение эффективнее и почему - Примечание: Без выполнения пунктов 2 и 3 задание считается нерешенным. Пункты 2 и 3 можно выполнить через строки документации в самом коде. @@ -13,8 +11,6 @@ а не писать "мы это не проходили)". Алгоритмизатор должен развивать мышление, а это прежде всего практика. А без столкновения со сложностями его не развить. - - Сама задача: Имеется хранилище с информацией о компаниях: название и годовая прибыль. Для реализации хранилища можно применить любой подход, @@ -22,3 +18,24 @@ Реализуйте поиск трех компаний с наибольшей годовой прибылью. Выведите результат. """ + +COMPANY_DICT = {"Марвел": 23587, "ДиСиКомикс": 54754, "Амбрелла": 2545549, "ДолгостройЛТД": 3153223, "МММ": 3465987} + +company_dict_values = list(COMPANY_DICT.values()) +company_dict_keys = list(COMPANY_DICT.keys()) +company_dict_values_2 = company_dict_values.copy() + +# 1 вариант - сложность O(n log n): +sorted_values = sorted(COMPANY_DICT.values(), reverse=True)[:3] # O(n log n) +for item in sorted_values: # O(1) + find_index = company_dict_values.index(item) # O(n) + max_key = company_dict_keys[find_index] + print(max_key) + +# 2 вариант - сложность O(n): +for i in range(3): # O(1) + max_value = max(company_dict_values_2) # O(n) + find_index = company_dict_values.index(max_value) # O(n) + max_key = company_dict_keys[find_index] # O(1) + print(max_key) + company_dict_values_2.remove(max_value) # O(n) diff --git "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" index d1193f62..9b8b65fc 100644 --- "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" +++ "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" @@ -1,11 +1,9 @@ """ Задание 4. - Для этой задачи: 1) придумайте 1-3 решения (желательно хотя бы два) 2) оцените сложность каждого решения в нотации О-большое 3) сделайте вывод, какое решение эффективнее и почему - Примечание: Без выполнения пунктов 2 и 3 задание считается нерешенным. Пункты 2 и 3 можно выполнить через строки документации в самом коде. @@ -13,17 +11,60 @@ а не писать "мы это не проходили)". Алгоритмизатор должен развивать мышление, а это прежде всего практика. А без столкновения со сложностями его не развить. - - Сама задача: Пользователи веб-ресурса проходят аутентификацию. В системе хранятся логин, пароль и отметка об активации учетной записи. - Нужно реализовать проверку, может ли пользователь быть допущен к ресурсу. При этом его учетка должна быть активирована. А если нет, то польз-лю нужно предложить ее пройти. - Приложение должно давать ответы на эти вопросы и быть реализовано в виде функции. Для реализации хранилища можно применить любой подход, который вы придумаете, например, реализовать словарь. """ + + +USER_DB_LIST = [{"login": "Sauron", "password": "BigEye", "auth": True}, + {"login": "Saruman", "password": "KillAllPeople", "auth": False}, + {"login": "Gendalf", "password": "uShallNotPass", "auth": False}] +USER_DB_DICT = {"Sauron": {"password": "BigEye", "auth": True}, + "Saruman": {"password": "KillAllPeople", "auth": False}, + "Gendalf": {"passw": "uShallNotPass", "auth": False}} + + +# Первый вариант - сложность O(n): +def check_user_first(user_name, user_pass): + for user in USER_DB_LIST: # O(n) + if user["login"] == user_name: # O(1) + if user["password"] == user_pass: # O(1) + if user["auth"]: # O(1) + print('Welcome To Midgard!') + break + else: + print('Активируйтесь!') + break + else: + print('Вы наколдовали неверный пароль!') + break + else: + print('Такого волшебника не существует!') + + +check_user_first(input('Ваше Имя на Эльфийском: '), input('Наколдуйте пароль: ')) + + +# Второй вариант - сложность O(1): +def check_user_second(user_name, user_pass): + user = USER_DB_DICT.get(user_name) # O(1) + if user is not None: # O(1) + if user["password"] == user_pass: # O(1) + if user["auth"]: # O(1) + print('Welcome To Midgard!') + else: + print('Активируйтесь!') + else: + print('Вы наколдовали неверный пароль!') + else: + print('Такого волшебника не существует!') + + +check_user_second(input('Ваше Имя на Эльфийском: '), input('Наколдуйте пароль: ')) diff --git "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_5.py" "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_5.py" index 291af805..4b8fceca 100644 --- "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_5.py" +++ "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_5.py" @@ -1,20 +1,72 @@ """ Задание 6. Задание на закрепление навыков работы со стеком - Примечание: в этом задании вспомните ваши знания по работе с ООП и опирайтесь на пример урока - Реализуйте структуру "стопка тарелок". - Мы можем складывать тарелки в стопку и при превышении некоторого значения нужно начать складывать тарелки в новую стопку. - Структура должна предусматривать наличие нескольких стеков. Создание нового стека происходит при достижении предыдущим стеком порогового значения. Реализуйте по аналогии с примером, рассмотренным на уроке, необходимые методы, для реализации это структуры, добавьте новые методы (не рассмотренные в примере с урока) для реализации этой задачи. - После реализации структуры, проверьте ее работу на различных сценариях """ + + +class StackClass: + def __init__(self): + self.elements_list = [] + + def is_empty(self): + return self.elements_list == [] + + def push_in(self, element): + """Предполагаем, что верхний элемент стека находится в конце списка""" + self.elements_list.append(element) + + def pop_out(self): + return self.elements_list.pop() + + def get_val(self): + return self.elements_list[len(self.elements_list) - 1] + + def stack_size(self): + return len(self.elements_list) + + +class Plates: + def __init__(self): + self.my_stack_list = [] + new_obj = StackClass() + self.my_stack_list.append(new_obj) + + def add_plate(self, element): + if self.my_stack_list[len(self.my_stack_list) - 1].stack_size() < 4: # 1 стопка = 4 тарелки + self.my_stack_list[len(self.my_stack_list) - 1].push_in(element) + else: + new_obj = StackClass() + self.my_stack_list.append(new_obj) + new_obj.push_in(element) + + def stack_count(self): + return len(self.my_stack_list) + + def plates_in_last_stack(self): + return self.my_stack_list[len(self.my_stack_list) - 1].stack_size() + + +ExObject = Plates() + +while True: + new_element = input('Добавить тарелку?(y/n): ') + if new_element == 'n': + print('Как хотите :)') + break + elif new_element == 'y': + ExObject.add_plate('Plate') + print(f'Всего стопок: {ExObject.stack_count()}') + print(f'Тарелок в последней стопке: {ExObject.plates_in_last_stack()}') + else: + print('Ответ может быть y или n') diff --git "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_6.py" "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_6.py" index 37594599..cb0e0b04 100644 --- "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_6.py" +++ "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_6.py" @@ -1,17 +1,89 @@ """ Задание 7. Задание на закрепление навыков работы с очередью - Примечание: в этом задании вспомните ваши знания по работе с ООП и опирайтесь на пример урока - Реализуйте структуру "доска задач". - - Структура должна предусматривать наличие несольких очередей задач, например 1) базовой, откуда задачи берутся, решаются и отправляются в список решенных 2) очередь на доработку, когда нерешенные задачи из первой очереди отправляются на корректировку решения - После реализации структуры, проверьте ее работу на различных сценариях """ + + +class QueueClass: + def __init__(self): + self.elements_list = [] + + def is_empty(self): + return self.elements_list == [] + + def to_queue(self, item): + self.elements_list.insert(0, item) + + def from_queue(self): + return self.elements_list.pop() + + def get_item(self): + return self.elements_list[-1] + + def size(self): + return len(self.elements_list) + + +class Kanban: + def __init__(self): + self.base_tasks = QueueClass() + self.other_tasks = QueueClass() + self.closed_tasks = [] + + def add_task(self, task): + self.base_tasks.to_queue(task) + + def close_task(self): + task = self.base_tasks.from_queue() + self.closed_tasks.append(task) + return task + + def rework_task(self): + task = self.base_tasks.from_queue() + print(f'На доработку отправлена: {task}') + self.other_tasks.to_queue(task) + + def get_task(self): + task = self.base_tasks.get_item() + return task + + def count_task(self): + return self.base_tasks.size(), self.other_tasks.size(), len(self.closed_tasks) + + +ExObject = Kanban() + +while 1 == 1: + to_base_q, to_rework_q, done_q = ExObject.count_task() + print(f'В базовой очереди: {to_base_q} задач\nНа доработку: {to_rework_q}\nЗадач уже выполнено: {done_q}') + try: + print(f'Что будем делать с задачей: {ExObject.get_task()}?') + except IndexError: + print('Задач пока нет') + option = input(f'Добавить задачу - нажмите 1, отметить как решенную - 2, на доработку - 3, выход - 4: ') + if len(option) == 0: + break + if option == "1": + ExObject.add_task(input('Введите задачу: ')) + elif option == "2": + try: + ExObject.close_task() + except IndexError: + print('Сначала добавь задачу') + elif option == "3": + try: + ExObject.rework_task() + except IndexError: + print('Сначала добавь задачу') + elif option == "4": + break + else: + print('Неверная команда!') diff --git "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_7.py" "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_7.py" index 7f75aaa4..73a77f0f 100644 --- "a/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_7.py" +++ "b/\320\243\321\200\320\276\320\272 1. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_7.py" @@ -1,12 +1,55 @@ """ Задание 5. Задание на закрепление навыков работы с деком - В рассмотренном на уроке листинге есть один недостаток Приведенный код способен "обработать" только строку без пробелов, например, 'топот' - Но могут быть и такие палиндромы, как 'молоко делили ледоколом' - Вам нужно доработать программу так, чтобы она могла выполнить проверку на палиндром и в таких строках (включающих пробелы) """ + + +class DequeClass: + def __init__(self): + self.elements = [] + + def is_empty(self): + return self.elements == [] + + def add_to_front(self, elem): + self.elements.append(elem) + + def add_to_rear(self, elem): + self.elements.insert(0, elem) + + def remove_from_front(self): + return self.elements.pop() + + def remove_from_rear(self): + return self.elements.pop(0) + + def size(self): + return len(self.elements) + + +# палиндром + +def pal_checker(string): + deq_object = DequeClass() + + for letter in string: + if letter != " ": + deq_object.add_to_rear(letter) + + still_equal = True + + while deq_object.size() > 1 and still_equal: + first = deq_object.remove_from_front() + last = deq_object.remove_from_rear() + if first != last: + still_equal = False + + return still_equal + + +print(pal_checker("молоко делили ледоколом")) diff --git "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" index eaea0088..791b9263 100644 --- "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" +++ "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" @@ -6,18 +6,14 @@ в качестве знака операции. Если пользователь вводит неверный знак (не '0', '+', '-', '*', '/'), то программа должна сообщать ему об ошибке и снова запрашивать знак операции. - Также сообщать пользователю о невозможности деления на ноль, если он ввел 0 в качестве делителя. - Подсказка: Вариант исполнения: - условие рекурсивного вызова - введена операция +, -, *, / - условие завершения рекурсии - введена операция 0 - Решите через рекурсию. Решение через цикл не принимается. Для оценки Отлично в этом блоке необходимо выполнить 5 заданий из 7 - Пример: Введите операцию (+, -, *, / или 0 для выхода): + Введите первое число: 214 @@ -28,3 +24,65 @@ Вы вместо трехзначного числа ввели строку (((. Исправьтесь Введите операцию (+, -, *, / или 0 для выхода): """ + + +def plus(a, b): + if b == 0: + return a + else: + return plus(a, b - 1) + 1 + + +def minus(a, b): + if b == 0: + return a + else: + return minus(a, b - 1) - 1 + + +def multi(a, b): + if b == 1: + return a + else: + return multi(a, b - 1) + a + + +def divide(a, b, r=0): + if a < b: + return r + elif b == 0: + return print('На ноль делить нельзя!') + else: + return divide(a - b, b, r + 1) + + +def calc(): + operation = input('Введите операцию (+, -, *, / или 0 для выхода): ') + if operation not in ('+', '-', '/', '*', '0'): + print('Ошибка при выборе знака операции.') + else: + if operation == '0': + return + try: + first = int(input('Введите первое число: ')) + except ValueError: + print('Это не число!') + try: + second = int(input('Введите второе число: ')) + except ValueError: + print('Это не число!') + else: + if operation == '+' and first > 0 and second > 0: + print(f'Ваш результат: {plus(first, second)}') + elif operation == '-' and first > 0 and second > 0: + print(f'Ваш результат: {minus(first, second)}') + elif operation == '*' and first > 0 and second > 0: + print(f'Ваш результат: {multi(first, second)}') + elif operation == '/' and first > 0 and second > 0: + print(f'Ваш результат: {divide(first, second)}') + else: + print('Непредвиденная ошибка.') + calc() + + +calc() diff --git "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" index c0840774..c25735fe 100644 --- "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" +++ "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" @@ -2,17 +2,35 @@ 2. Посчитать четные и нечетные цифры введенного натурального числа. Например, если введено число 34560, то у него 3 четные цифры (4, 6 и 0) и 2 нечетные (3 и 5). - Подсказка: На каждом шаге вам нужно 'доставать' из числа очередную цифру и смотреть является ли она четной или нечетной. При этом увеличиваем соответствующий счетчик Пока все числа не извлечены рекурсивные вызовы продолжаем Условие завершения рекурсии - все числа извлечены - Решите через рекурсию. Решение через цикл не принимается. Для оценки Отлично в этом блоке необходимо выполнить 5 заданий из 7 - Пример: Введите число: 123 Количество четных и нечетных цифр в числе равно: (1, 2) """ + +a = int(input('Введите длинное число: ')) + +even = 0 +odd = 0 + + +def fun(num): + global even, odd + if num == 0: + return + if num % 2 == 0: + even += 1 + else: + odd += 1 + a = num // 10 + fun(a) + + +fun(a) +print(f"Четных: {even}, нечетных: {odd}") diff --git "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" index a3f170d6..7955f53f 100644 --- "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" +++ "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" @@ -2,16 +2,26 @@ 3. Сформировать из введенного числа обратное по порядку входящих в него цифр и вывести на экран. Например, если введено число 3486, то надо вывести число 6843. - Подсказка: На каждом шаге вам нужно 'доставать' из числа очередную цифру Пока все числа не извлечены рекурсивные вызовы продолжаем Условие завершения рекурсии - все числа извлечены - Решите через рекурсию. Решение через цикл не принимается. Для оценки Отлично в этом блоке необходимо выполнить 5 заданий из 7 - Пример: Введите число, которое требуется перевернуть: 123 Перевернутое число: 321 """ + + +def fun(a): + if a == 0: + return + print(a % 10, end='') + a = a // 10 + fun(a) + + +a = int(input('Введите число, которое требуется перевернуть: ')) +print('Перевернутое число: ', end='') +fun(a) \ No newline at end of file diff --git "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" index 83482bdd..fe03600f 100644 --- "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" +++ "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" @@ -1,11 +1,19 @@ """ 4. Найти сумму n элементов следующего ряда чисел: 1 -0.5 0.25 -0.125 ... Количество элементов (n) вводится с клавиатуры. - Пример: Введите количество элементов: 3 Количество элементов - 3, их сумма - 0.75 - Решите через рекурсию. Решение через цикл не принимается. Для оценки Отлично в этом блоке необходимо выполнить 5 заданий из 7 """ + + +def fun(i, a=1): + if i == 0: + return 0 + return a + fun(i-1, a / (-2)) + + +n = int(input('Введите количество элементов: ')) +print(f'Количество элементов - {n}, их сумма - {fun(n)}') diff --git "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_5.py" "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_5.py" index 89942335..f206e8af 100644 --- "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_5.py" +++ "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_5.py" @@ -14,7 +14,18 @@ 102 - f 103 - g 104 - h 105 - i 106 - j 107 - k 108 - l 109 - m 110 - n 111 - o 112 - p 113 - q 114 - r 115 - s 116 - t 117 - u 118 - v 119 - w 120 - x 121 - y 122 - z 123 - { 124 - | 125 - } 126 - ~ 127 -  - Решите через рекурсию. Решение через цикл не принимается. Для оценки Отлично в этом блоке необходимо выполнить 5 заданий из 7 """ + + +def char_group(ascii_sym=32): + if ascii_sym == 128: + return + print(f'{ascii_sym} - {chr(ascii_sym)} ', end='') + if (ascii_sym - 31) % 10 == 0: + print('\n') + char_group(ascii_sym + 1) + + +char_group() diff --git "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_6.py" "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_6.py" index 5d5f0035..e1e442aa 100644 --- "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_6.py" +++ "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_6.py" @@ -9,3 +9,24 @@ Для оценки Отлично в этом блоке необходимо выполнить 5 заданий из 7 Для оценки Отлично в этом блоке необходимо выполнить 5 заданий из 7 """ +import random + +n = random.randint(0, 100) + + +def fun(i=0): + if i == 5: + print(f'Количество попыток исчерпано! Было загадано число {n}.') + return + user_number = int(input('Введите число: ')) + if n == user_number: + print(f'Вы угадали, загаданное число - {n}') + elif n < user_number: + print(f'Заданное число меньше, чем то, что вы написали.') + fun(i+1) + else: + print(f'Заданное число больше, чем то, что вы написали.') + fun(i+1) + + +fun() diff --git "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_7.py" "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_7.py" index 7bd6493a..2812ff60 100644 --- "a/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_7.py" +++ "b/\320\243\321\200\320\276\320\272 2. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_7.py" @@ -2,7 +2,19 @@ 7. Напишите программу, доказывающую или проверяющую, что для множества натуральных чисел выполняется равенство: 1+2+...+n = n(n+1)/2, где n - любое натуральное число. - Решите через рекурсию. Решение через цикл не принимается. Для оценки Отлично в этом блоке необходимо выполнить 5 заданий из 7 """ + +n = int(input('Введите значение n: ')) + + +def fun(i): + if i == 0: + return 0 + return i + fun(i-1) + + +m = int(n * (n + 1) / 2) +print(f'Значение функции 1+2+...+n, где n = {n} равно {fun(n)}. ' + f'Что также равно функции n(n+1)/2 - {m}. Равенство выполняется!') \ No newline at end of file diff --git "a/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" "b/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" index 55755352..c464ec67 100644 --- "a/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" +++ "b/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" @@ -1,12 +1,57 @@ """ Задание 1. - Реализуйте заполнение списка и словаря, сделайте замеры и сделайте выводы, обоснуйте результат. Сделайте несколько операций с каждым из объектов, сделайте замеры и сделайте выводы, обоснуйте результат. - Подсказка: для замеров воспользуйтесь модулем time (см. примеры урока 1) - Примечание: eсли вы уже знаете, что такое декоратор и как его реализовать, то реализуйте ф-цию-декоратор и пусть она считает время И примените ее к двум своим функциям. """ +from time import process_time + + +def benchmark(func): + def wrapper(*args, **kwargs): + time = process_time() + result = func(*args, **kwargs) + print(func.__name__, process_time() - time) + return result + return wrapper + + +range_list = [element for element in range(1, 10000000)] +range_dict = {element: element for element in range(1, 10000000)} + + +@benchmark +def multi_list(input_list): + print('для списка: ') + return [element * 2 for element in input_list] + + +@benchmark +def multi_dict(input_dict): + print('и для словаря: ') + return {key: value * 2 for key, value in input_dict.items()} + + +@benchmark +def div_list(input_list): + print('для списка: ') + return [element // 2 for element in input_list] + + +@benchmark +def div_dict(input_dict): + print('и для словаря: ') + return {key: value // 2 for key, value in input_dict.items()} + + +print('Умножение...') +multi_list(range_list) +multi_dict(range_dict) +print('Деления без остатка...') +div_list(range_list) +div_dict(range_dict) + +print('Во всех случаях операции со словарем проходят дольше!') \ No newline at end of file diff --git "a/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" "b/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" index 7877a7df..0d6b390a 100644 --- "a/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" +++ "b/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" @@ -4,14 +4,42 @@ Для этого пароля вам нужно получить хеш, используя функцию sha256 Для генерации хеша обязательно нужно использовать криптографическую соль Обязательно выведите созданный хеш - Далее программа должна запросить пароль повторно Вам нужно проверить, совпадает ли пароль с исходным Для проверки необходимо сравнить хеши паролей - ПРИМЕР: Введите пароль: 123 В базе данных хранится строка: 555a3581d37993843efd4eba1921f1dcaeeafeb855965535d77c55782349444b Введите пароль еще раз для проверки: 123 Вы ввели правильный пароль """ +from hashlib import pbkdf2_hmac +from binascii import hexlify + +user_data_first = input('Введите пароль: ').encode('utf-8') + +# Здесь мы создаем хеш sha256 в пароле при помощи соли со 100,000 итераций. +obj = pbkdf2_hmac(hash_name='sha256', + password=user_data_first, + salt=b'any_salt_1', + iterations=100000) +obj = pbkdf2_hmac(hash_name='sha256', + password=user_data_first, + salt=b'any_salt_2', + iterations=100000) +print(f'В базе данных хранится строка: {hexlify(obj)}') + + +user_data_second = input('Введите пароль еще раз для проверки: ').encode('utf-8') +obj_2 = pbkdf2_hmac(hash_name='sha256', + password=user_data_second, + salt=b'any_salt_1', + iterations=100000) +obj_2 = pbkdf2_hmac(hash_name='sha256', + password=user_data_second, + salt=b'any_salt_2', + iterations=100000) +if hexlify(obj) == hexlify(obj_2): + print('Вы ввели правильный пароль') +else: + print('Вы ввели неправильный пароль') \ No newline at end of file diff --git "a/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" "b/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" index ca72e990..b5068d76 100644 --- "a/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" +++ "b/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" @@ -2,11 +2,8 @@ Задание 3. Определить количество различных подстрок с использованием хеш-функции. Дана строка S длиной N, состоящая только из строчных латинских букв. - Подсказка: примените хеши и множества - рара: - рар ра ар @@ -14,3 +11,20 @@ р а """ + +import hashlib + + +def substrings(user_d): + set_substrings = set() + count = len(user_d) + for el in range(len(user_d)): + for i in range(len(user_d)): + if user_d not in user_d[i:i+count]: + set_substrings.add(hashlib.sha256(user_d[i:i+count].encode('utf-8')).hexdigest()) + count -= 1 + return set_substrings + + +user_data = input("Введите строку состоящую только из строчных латинских букв: ") +print(f"Количество подстрок: {len(substrings(user_data))}") diff --git "a/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" "b/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" index 4c6a5b7e..98e7a5e6 100644 --- "a/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" +++ "b/\320\243\321\200\320\276\320\272 3. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" @@ -1,10 +1,31 @@ """ Задание 4. Реализуйте скрипт "Кэширование веб-страниц" - Функция должна принимать url-адрес и проверять есть ли в кэше соответствующая страница, если нет, то вносит ее в кэш - Подсказка: задачу решите обязательно с применением 'соленого' хеширования Можете условжнить задачу, реализовав ее через ООП -""" \ No newline at end of file +""" +from hashlib import sha256 + + +class CacheWeb: + def __init__(self): + self.salt = b'any_salt' + self.obj = {} + + def get_page(self, url): + if self.obj.get(url): + print(f'Данный адрес: {url} присутствует в кэше') + else: + res = sha256(self.salt + url.encode()).hexdigest() + self.obj[url] = res + print(self.obj) + + +new_web = CacheWeb() + +new_web.get_page('https://habrahabr.ru/') +new_web.get_page('https://habrahabr.ru/') +new_web.get_page('https://google.com/') +new_web.get_page('https://google.com/') \ No newline at end of file diff --git "a/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" "b/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" index f6ffb4b9..e3c12b72 100644 --- "a/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" +++ "b/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" @@ -21,3 +21,25 @@ def func_1(nums): if nums[i] % 2 == 0: new_arr.append(i) return new_arr + + +def func_2(nums): + new_arr = [] + for i, x in enumerate(nums): + if x % 2 == 0: + new_arr.append(i) + return new_arr + + +my_list = [1894, 3332, 32, 1134] + +print('Начальный код:') +print(timeit(f"func_1({my_list})", setup="from __main__ import func_1", number=10000)) + +print('Оптимизированный код:') +print(timeit(f"func_2({my_list})", setup="from __main__ import func_2", number=10000)) + +""" +Смена на цикл по парам номер_элемента - значение. +нет операции обращения к элементу массива по номеру, следовательно быстрее. +""" diff --git "a/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" "b/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" index 307657c8..db548fe1 100644 --- "a/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" +++ "b/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" @@ -11,6 +11,7 @@ Если у вас есть идеи, предложите вариант оптимизации. """ + from timeit import timeit from random import randint @@ -47,7 +48,6 @@ def memoize(f): cache = {} def decorate(*args): - if args in cache: return cache[args] else: @@ -79,3 +79,17 @@ def recursive_reverse_mem(number): 'recursive_reverse_mem(num_10000)', setup='from __main__ import recursive_reverse_mem, num_10000', number=10000)) + +""" +В случае с тройной рекурсией, используя мемоизацию, мы избегаем повторных расчетов, +все берется из памяти, отсюда и оптимизация + +Не оптимизированная функция recursive_reverse +0.0186562 +0.0214113 +0.0394946 +Оптимизированная функция recursive_reverse_mem +0.001513500000000001 +0.0015310000000000046 +0.0015724000000000016 +""" \ No newline at end of file diff --git "a/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" "b/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" index 696f5ec1..08327c33 100644 --- "a/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" +++ "b/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" @@ -10,6 +10,9 @@ Сделайте вывод, какая из трех реализаций эффективнее и почему """ +from timeit import timeit +from cProfile import run + def revers(enter_num, revers_num=0): if enter_num == 0: @@ -34,3 +37,27 @@ def revers_3(enter_num): revers_num = enter_num[::-1] return revers_num + +number = 4264646724154745416546744124687464654351468764123164797 + +print('Функция revers:') +print(timeit(f"revers({number})", setup="from __main__ import revers", number=100000)) +run('revers(number)') + +print('Функция revers_2:') +print(timeit(f"revers_2({number})", setup="from __main__ import revers_2", number=100000)) +run('revers_2(number)') + +print('Функция revers_3:') +print(timeit(f"revers_3({number})", setup="from __main__ import revers_3", number=100000)) +run('revers_3(number)') + +""" +Первая рекурсивная функция revers выполняется дольше cProfile показывает, что функция вызывается 59 раз и +только 4 - без рекурсии. В моем примере - 1.22 секунды. + +Вторая WHILE функция revers_2 выполняется быстрее чем функция revers, написанная через рекурсию - 0.86 секунды. + +Победитель функция revers_3, написанная используя встроеные конструкции языка. Ее выполенение заняло 0.04 секунды. +Большой разрыв по времени относительно других функиций и чем больше число, тем больше разрыв. +""" \ No newline at end of file diff --git "a/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" "b/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" index a852f43c..c824efea 100644 --- "a/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" +++ "b/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" @@ -10,7 +10,10 @@ Сделайте замеры и опишите, получилось ли у вас ускорить задачу. """ -array = [1, 3, 1, 3, 4, 5, 1] +from timeit import timeit +from numpy import argmax, bincount + +array = [1, 3, 1, 3, 4, 5, 1, 1, 3, 1, 3, 4, 5, 1, 1, 3, 1, 3, 4, 5, 1, 1, 3, 1, 3, 4, 5, 1, 1, 3, 1, 3, 4, 5] def func_1(): @@ -37,5 +40,45 @@ def func_2(): f'оно появилось в массиве {max_2} раз(а)' +def func_3(): + m = 0 + num = 0 + for i in set(array): + count = array.count(i) + if count > m: + m = count + num = i + return f'Чаще всего встречается число {num}, ' \ + f'оно появилось в массиве {m} раз(а)' + + +def func_4(): + m = bincount(array) + num = argmax(m) + return f'Чаще всего встречается число {num},' \ + f'оно появилось в массиве {max(m)} раз(а)' + + +print('func_1') print(func_1()) +print(timeit("func_1()", setup="from __main__ import func_1", number=100000)) + +print('func_2') print(func_2()) +print(timeit("func_2()", setup="from __main__ import func_2", number=100000)) + +print('func_3') +print(func_3()) +print(timeit("func_3()", setup="from __main__ import func_3", number=100000)) + +print('func_4') +print(func_4()) +print(timeit("func_4()", setup="from __main__ import func_4", number=100000)) + +""" +func_3 получилась самая быстра из-за смены списка на множество уникальных элементов массива. +Время - 0.251с +func_4 использует модуль numpy, её приемущество в лаконичности кода, хоть и работает она медленнее чем func_3, +но быстрее первых двух +Время - 0.659 +""" diff --git "a/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_5.py" "b/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_5.py" index 4e4f58b2..e7923713 100644 --- "a/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_5.py" +++ "b/\320\243\321\200\320\276\320\272 4. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_5.py" @@ -14,6 +14,9 @@ Подумайте и по возможности определите сложность каждого алгоритма """ +from timeit import timeit +from math import log + def simple(i): """Без использования «Решета Эратосфена»""" @@ -35,5 +38,43 @@ def simple(i): return n +def sieve_eratosfen(nn): + """С использованием «Решета Эратосфена»""" + n = round(nn * log(nn)) * 2 + sieve = [True] * n + k = 0 + for i in range(2, n): + if sieve[i]: + k += 1 + if k == nn: + return i + j = i * 2 + while j < n: + sieve[j] = False + j += i + + i = int(input('Введите порядковый номер искомого простого числа: ')) -print(simple(i)) \ No newline at end of file +print('Без использования «Решета Эратосфена»:') +print(simple(i)) +print(timeit(f"simple({i})", setup="from __main__ import simple", number=100)) +print('C использованием «Решета Эратосфена»:') +print(sieve_eratosfen(i)) +print(timeit(f"sieve_eratosfen({i})", setup="from __main__ import sieve_eratosfen", number=100)) + + +""" +При подсчете 10 порядкового числа +Без использования «Решета Эратосфена» функция отрабатывает 0.00154 секунды +С использованием «Решета Эратосфена» функция отрабатывает 0.00055 секунды +При подсчете 100 порядкового числа +Без использования «Решета Эратосфена» функция отрабатывает 0.188 секунды +С использованием «Решета Эратосфена» функция отрабатывает 0.014 секунды +При подсчете 1000 порядкового числа +Без использования «Решета Эратосфена» функция отрабатывает 31.18 секунды +С использованием «Решета Эратосфена» функция отрабатывает 0.25 секунды +С решетом в разы быстрее. Чем больше число, тем больше разрыв по времени. + +Алгоритма Эратосфена O(n log(log(n)) +Двойного цикл - O(n**2) +""" \ No newline at end of file diff --git "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" index 82b46bcf..87e81539 100644 --- "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" +++ "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" @@ -25,3 +25,27 @@ Предприятия, с прибылью ниже среднего значения: Копыта """ +from collections import namedtuple + +COMPANY = namedtuple('Company', 'name q1 q2 q3 q4') +count_comp = int(input('Введите количество предприятий для расчета прибыли: ')) +company_list = [] +income_y_dict = {} +for i in range(count_comp): + name = input('Введите название предприятия: ') + income_str = input('через пробел введите прибыль данного предприятия \n ' + + 'за каждый квартал (Всего 4 квартала): ') + income = list(map(float, income_str.split())) + my_company = COMPANY(name=name, q1=income[0], q2=income[1], q3=income[2], q4=income[3]) + company_list.append(my_company) +for my_company in company_list: + income_year = my_company.q1+my_company.q2+my_company.q3+my_company.q4 + income_y_dict[my_company.name] = income_year + +avg_income = sum(income_y_dict.values()) / count_comp + +print(f'Средняя годовая прибыль всех предприятий: {avg_income}') +print('Предприятия, с прибылью выше среднего значения: ', + [name for name, inc in income_y_dict.items() if inc > avg_income]) +print('Предприятия, с прибылью ниже среднего значения: ', + [name for name, inc in income_y_dict.items() if inc <= avg_income]) diff --git "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" index 35add0f1..9838b37f 100644 --- "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" +++ "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" @@ -11,3 +11,23 @@ Также попробуйте решить задачу вообще без collections и применить только ваши знания по ООП (в частности по перегрузке методов) """ +from collections import defaultdict +from functools import reduce + + +def hex_calc(): + numbers = defaultdict(list) + input_first = input('Введи первое hex число: ') + input_second = input('Введи второе hex число: ') + numbers[f'1={input_first}'] = list(input_first) + numbers[f'2={input_second}'] = list(input_second) + print(numbers) + sum_of_hex = sum([int(''.join(i), 16) for i in numbers.values()]) + print(sum_of_hex) + print('Сумма :', list('%X' % sum_of_hex)) + multiply_of_hex = reduce(lambda a, b: a * b, [int(''.join(i), 16) for i in numbers.values()]) + print('Произведение: ', list('%X' % multiply_of_hex)) + + +hex_calc() + diff --git "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" index dd1c82f3..75d626af 100644 --- "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" +++ "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" @@ -9,4 +9,74 @@ Выполните различные операции с каждым из объектов. Сделайте замеры и оцените, насколько информация в документации соответствует дейстивтельности. -""" \ No newline at end of file +""" +from collections import deque +from timeit import timeit + +n = 20000 +my_list = [element for element in range(n)] +my_deque = deque(my_list) + + +def list_add(): + my_list.append(1) + + +def deque_add(): + my_deque.append(1) + + +def deque_add_left(): + my_deque.appendleft(1) + + +def list_add_left(): + global my_list + my_list = [1] + my_list + + +def deque_del(): + my_deque.pop() + + +def list_del(): + my_list.pop() + + +def deque_del_left(): + my_deque.popleft() + + +def list_del_left(): + global my_list + my_list = my_list[1:] + + +print('Добавление через list: ', + timeit("list_add()", setup="from __main__ import list_add", number=n)) +print('Добавление через deque: ', + timeit("deque_add()", setup="from __main__ import deque_add", number=n)) +print('Добавление слева через list: ', + timeit("list_add_left()", setup="from __main__ import list_add_left", number=n)) +print('Добавление слева через deque: ', + timeit("deque_add_left()", setup="from __main__ import deque_add_left", number=n)) +print('Удаление через list: ', + timeit("list_del()", setup="from __main__ import list_del", number=n)) +print('Удаление через deque: ', + timeit("deque_del()", setup="from __main__ import deque_del", number=n)) +print('Удаление слева через list: ', + timeit("list_del_left()", setup="from __main__ import list_del_left", number=n)) +print('Удаление слева через deque: ', + timeit("deque_del_left()", setup="from __main__ import deque_del_left", number=n)) + +""" +При обычном добавлении разница минимальная, но при удалении и добавлении слева разница становится существенной. +Добавление через list: 0.0026205 +Добавление через deque: 0.0022240000000000003 +Добавление слева через list: 3.5336189 +Добавление слева через deque: 0.0023341000000001166 +Удаление через list: 0.002456100000000294 +Удаление через deque: 0.002163799999999938 +Удаление слева через list: 1.7133153 +Удаление слева через deque: 0.002170500000000075 +""" diff --git "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" index 13ec157f..1d2e0a0a 100644 --- "a/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" +++ "b/\320\243\321\200\320\276\320\272 5. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_4.py" @@ -3,4 +3,61 @@ Поработайте с обычным словарем и OrderedDict. Выполните различные операции с каждым из объектов и сделайте замеры. Опишите полученные результаты, сделайте выводы. -""" \ No newline at end of file +""" +from collections import OrderedDict +from timeit import timeit + +n = 100000 +my_dict = {element: element for element in range(n)} +my_order_dict = OrderedDict(my_dict) + + +def dict_keys(): + my_dict.keys() + + +def o_dict_keys(): + my_order_dict.keys() + + +def dict_val(): + my_dict.values() + + +def o_dict_val(): + my_order_dict.values() + + +def dict_upd(): + my_dict.update({'2': '3'}) + + +def o_dict_upd(): + my_order_dict.update({'2': '3'}) + + +print('Получение ключей через обычный словарь: ', + timeit("dict_keys()", setup="from __main__ import dict_keys", number=n)) +print('Получение ключей через OrderedDict: ', + timeit("o_dict_keys()", setup="from __main__ import o_dict_keys", number=n)) +print('Получение значений через обычный словарь: ', + timeit("dict_val()", setup="from __main__ import dict_val", number=n)) +print('Получение значений через OrderedDict: ', + timeit("o_dict_val()", setup="from __main__ import o_dict_val", number=n)) +print('Добавление в обычный словарь: ', + timeit("dict_upd()", setup="from __main__ import dict_upd", number=n)) +print('Добавление в OrderedDict: ', + timeit("o_dict_upd()", setup="from __main__ import o_dict_upd", number=n)) + +""" +Получение ключей через обычный словарь: 0.0119448 +Получение ключей через OrderedDict: 0.0121557 +Получение значений через обычный словарь: 0.0123044 +Получение значений через OrderedDict: 0.012166999999999997 +Добавление в обычный словарь: 0.0217081 +Добавление в OrderedDict: 0.0316023 + + +OrderedDict проигрывает обычному словарю, кроме одного замера и то скорее всего случайно, но есть у него и плюсы, +скорее всего в своих проектах иногда буду его использовать. +""" diff --git "a/\320\243\321\200\320\276\320\272 6. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" "b/\320\243\321\200\320\276\320\272 6. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" index 4bfb8a82..4409792e 100644 --- "a/\320\243\321\200\320\276\320\272 6. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" +++ "b/\320\243\321\200\320\276\320\272 6. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" @@ -13,3 +13,110 @@ ВНИМАНИЕ: ЗАДАНИЯ, В КОТОРЫХ БУДУТ ГОЛЫЕ ЦИФРЫ ЗАМЕРОВ (БЕЗ АНАЛИТИКИ) БУДУТ ПРИНИМАТЬСЯ С ОЦЕНКОЙ УДОВЛЕТВОРИТЕЛЬНО """ +from memory_profiler import profile +from math import log +from platform import architecture +from sys import version +from numpy import argmax, bincount + +# Разрядность 64bit +# Версия Python 3.6.5 + + +array = [1, 3, 1, 3, 4, 5, 1, 1, 3, 1, 3, 4, 5, 1, 1, 3, 1, 3, 4, 5, 1, 1, 3, 1, 3, 4, 5, 1, 1, 3, 1, 3, 4, 5] + + +@profile(precision=4) +def func_1(): + m = 0 + num = 0 + for i in array: + count = array.count(i) + if count > m: + m = count + num = i + return f'Чаще всего встречается число {num}, ' \ + f'оно появилось в массиве {m} раз(а)' + + +@profile(precision=4) +def func_2(): + new_array = [] + for el in array: + count2 = array.count(el) + new_array.append(count2) + + max_2 = max(new_array) + elem = array[new_array.index(max_2)] + return f'Чаще всего встречается число {elem}, ' \ + f'оно появилось в массиве {max_2} раз(а)' + + +@profile(precision=4) +def func_3(): + m = 0 + num = 0 + for i in set(array): + count = array.count(i) + if count > m: + m = count + num = i + return f'Чаще всего встречается число {num}, ' \ + f'оно появилось в массиве {m} раз(а)' + + +@profile(precision=4) +def func_4(): + m = bincount(array) + num = argmax(m) + return f'Чаще всего встречается число {num},' \ + f'оно появилось в массиве {max(m)} раз(а)' + + +print(func_1()) +print(func_2()) +print(func_3()) +print(func_4()) + +""" +По первым двум функциям понятно, что они очень затратны в плане ресурсов процессора, но по памяти ничего не меняется + +По профайлеру видно, что использование методов модуля numpy требует незначительно больше памяти хоть +с каждым разом и уменьшает increment, но ускоряет процесс за счет еденичных повторений кода в отличие от первых +двух функций. Использование этого варината обосновано в тех случаях, когда модуль numpy уже используется в проекте +где либо еще, в противном случае использование приведет к лишнему весу приложения. + +func_4 +Line # Mem usage Increment Occurences Line Contents +============================================================ + 68 32.0195 MiB 32.0195 MiB 1 @profile(precision=4) + 69 def func_4(): + 70 32.0312 MiB 0.0117 MiB 1 m = bincount(array) + 71 32.0391 MiB 0.0078 MiB 1 num = argmax(m) + 72 32.0430 MiB 0.0039 MiB 1 return f'Чаще всего встречается число {num},' \ + 73 f'оно появилось в массиве {max(m)} раз(а)' + + +Чаще всего встречается число 1,оно появилось в массиве 14 раз(а) +================================================================= +func_3 же оптимальный результат здесь, держит память на одном уровне и соблюдает баланс по количеству повторений +Я бы предпочел использовать третий результат, так как функции все встроенные и их возможностей достаточно +для решения задачи + +Line # Mem usage Increment Occurences Line Contents +============================================================ + 55 32.0195 MiB 32.0195 MiB 1 @profile(precision=4) + 56 def func_3(): + 57 32.0195 MiB 0.0000 MiB 1 m = 0 + 58 32.0195 MiB 0.0000 MiB 1 num = 0 + 59 32.0195 MiB 0.0000 MiB 5 for i in set(array): + 60 32.0195 MiB 0.0000 MiB 4 count = array.count(i) + 61 32.0195 MiB 0.0000 MiB 4 if count > m: + 62 32.0195 MiB 0.0000 MiB 1 m = count + 63 32.0195 MiB 0.0000 MiB 1 num = i + 64 32.0195 MiB 0.0000 MiB 1 return f'Чаще всего встречается число {num}, ' \ + 65 f'оно появилось в массиве {m} раз(а)' + + +Чаще всего встречается число 1,оно появилось в массиве 14 раз(а) +""" diff --git "a/\320\243\321\200\320\276\320\272 6. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" "b/\320\243\321\200\320\276\320\272 6. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" index 3369970b..3f1a9dc7 100644 --- "a/\320\243\321\200\320\276\320\272 6. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" +++ "b/\320\243\321\200\320\276\320\272 6. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" @@ -5,3 +5,78 @@ Например, один из вариантов, использование генераторов """ +import sys +from memory_profiler import profile + + +class BaseOfHumans(object): + def __init__(self, name, age, address): + self.name = name + self.age = age + self.address = address + + +class BaseOfHumansSlots(object): + __slots__ = ['name', 'age', 'address'] + + def __init__(self, name, age, address): + self.name = name + self.age = age + self.address = address + + +@profile(precision=4) +def func_1(name, age, address): + data = [] + for i in range(100000): + data.append(BaseOfHumans(name, age, address)) + return data + + +@profile(precision=4) +def func_2(name, age, address): + data = [] + for i in range(100000): + data.append(BaseOfHumansSlots(name, age, address)) + return data + + +fn1 = func_1("Петя", 32, "Какой-то адрес") +fn2 = func_2("Петя", 32, "Какой-то адрес") +print(sys.getsizeof(fn1), sys.getsizeof(fn2)) + +""" +Использование модуля itertools уже известно многим (говорили на следующем уроке), я хочу предложить не совсем +фундаментальное, но очень интересное решение, я пойму, если вы не примите это как выполенение задания 2:) + +Есть интересная директива __slots__ прописанная в доках по Python, она помогает нам явно объявлять элементы данных +такие как параметры и запрещает использование __dict__ и __weakref__(слабая ссылка) что может существенно сэкономить +память. +На примере видно, что класс с использованием __slots__ во второй функции экономит память почти в 3 раза. +учитывая, что мы имеем список с боллее 100тыс элементов. Но такой подход нельзя использовать, если мы хотим +в дальнейшем добавлять поля в наш список не изменяя класс. У всего есть свои минусы.. + +Вывод без директивы __slots__: +Line # Mem usage Increment Occurences Line Contents +============================================================ + 28 20.1680 MiB 20.1680 MiB 1 @profile(precision=4) + 29 def func_1(name, age, address): + 30 20.1680 MiB 0.0000 MiB 1 data = [] + 31 38.2227 MiB 0.0000 MiB 100001 for p in range(100000): + 32 38.2227 MiB 18.0547 MiB 100000 data.append(BaseOfHumans(name, age, address)) + 33 38.2227 MiB 0.0000 MiB 1 return data + +Вывод c директивой: +Line # Mem usage Increment Occurences Line Contents +============================================================ + 36 38.2344 MiB 38.2344 MiB 1 @profile(precision=4) + 37 def func_2(name, age, address): + 38 38.2344 MiB 0.0000 MiB 1 data = [] + 39 45.1484 MiB 0.0000 MiB 100001 for p in range(100000): + 40 45.1484 MiB 6.9141 MiB 100000 data.append(BaseOfHumansSlots(name, age, address)) + 41 45.1484 MiB 0.0000 MiB 1 return data + +При этом sys.getsizeof показывает нам одинаковый размер: +без директивы: 824464 +с директивой: 824464 +""" diff --git "a/\320\243\321\200\320\276\320\272 6. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" "b/\320\243\321\200\320\276\320\272 6. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" new file mode 100644 index 00000000..c18a88b3 --- /dev/null +++ "b/\320\243\321\200\320\276\320\272 6. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" @@ -0,0 +1,40 @@ +""" +Задание 3 *. +Сделать профилировку для скриптов с рекурсией и сделать описание, +можно ли так профилировать и есть ли 'подводные камни' в профилировании? +Придумать как это решить! +Есть очень простое решение! +""" +from memory_profiler import profile + + +def recursive(num): + global even, odd + if num == 0: + return + if num % 2 == 0: + even += 1 + else: + odd += 1 + a = num // 10 + recursive(a) + + +@profile(precision=4) +def recursive_wrapper(a): + return recursive(a) + + +a = int(input('Введите длинное число: ')) + +even = 0 +odd = 0 + +recursive_wrapper(a) +print(f"Четных: {even}, нечетных: {odd}") + +""" +профайлер будет запускаться столько раз сколько будет запускать себя рекурсивная функция +для избежания этого нужна другая функция запускающая рекурсию +""" + diff --git "a/\320\243\321\200\320\276\320\272 7. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" "b/\320\243\321\200\320\276\320\272 7. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" index 72a810e8..4738496c 100644 --- "a/\320\243\321\200\320\276\320\272 7. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" +++ "b/\320\243\321\200\320\276\320\272 7. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" @@ -12,3 +12,59 @@ Подсказка: обратите внимание, сортируем не по возрастанию, как в примере, а по убыванию """ +from timeit import timeit +from random import randint + + +def bubble_sort1(lst_obj): + n = 1 + while n < len(lst_obj): + for i in range(len(lst_obj)-n): + if lst_obj[i] < lst_obj[i+1]: + lst_obj[i], lst_obj[i+1] = lst_obj[i+1], lst_obj[i] + n += 1 + return lst_obj + + +def bubble_sort2(lst_obj): + n = 1 + while n < len(lst_obj): + flag = True + for i in range(len(lst_obj)-n): + if lst_obj[i] < lst_obj[i+1]: + lst_obj[i], lst_obj[i+1] = lst_obj[i+1], lst_obj[i] + flag = False + if flag: + return lst_obj + n += 1 + return lst_obj + + +orig_list = [randint(-100, 100) for _ in range(10)] +print(f'Оригинальный список: \n{orig_list}') +print(f'Список, отсортированный методом "пузырька" в порядке убывания без доработки: \n{bubble_sort1(orig_list)}') +print(f'Список, отсортированный методом "пузырька" в порядке убывания после доработки: \n{bubble_sort2(orig_list)}') + +# замеры 10 +print('Замеры функции без доработки:') +print( + timeit( + "bubble_sort1(orig_list[:])", + globals=globals(), + number=1000)) + +print('Замеры функции после доработки:') +print( + timeit( + "bubble_sort2(orig_list[:])", + globals=globals(), + number=1000)) + +""" +Оптимизация ускорила время выполнения в несколько раз. Заметно это станет при обработке больших массивов. +Замеры функции без доработки: +0.0060652 +Замеры функции после доработки: +0.0010644999999999995 +""" + diff --git "a/\320\243\321\200\320\276\320\272 7. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" "b/\320\243\321\200\320\276\320\272 7. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" index 73d3dfb6..b8240c42 100644 --- "a/\320\243\321\200\320\276\320\272 7. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" +++ "b/\320\243\321\200\320\276\320\272 7. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" @@ -8,3 +8,45 @@ Исходный - [46.11436617832828, 41.62921998361278, 18.45859540989644, 12.128870723745806, 8.025098788570562] Отсортированный - [8.025098788570562, 12.128870723745806, 18.45859540989644, 41.62921998361278, 46.11436617832828] """ +from random import random + + +def merge_sort(lst_obj): + if len(lst_obj) > 1: + center = len(lst_obj) // 2 + left = lst_obj[:center] + right = lst_obj[center:] + + merge_sort(left) + merge_sort(right) + + # перестали делить + # выполняем слияние + i, j, k = 0, 0, 0 + + while i < len(left) and j < len(right): + if left[i] < right[j]: + lst_obj[k] = left[i] + i += 1 + else: + lst_obj[k] = right[j] + j += 1 + k += 1 + + while i < len(left): + lst_obj[k] = left[i] + i += 1 + k += 1 + + while j < len(right): + lst_obj[k] = right[j] + j += 1 + k += 1 + return lst_obj + + +count_of_elements = int(input('Введите число элементов: ')) +orig_list = [random()*50 for _ in range(count_of_elements)] +print(f'Оригинальный список: \n{orig_list}') +print(f'Список, отсортированный методом слияния: \n{merge_sort(orig_list)}') + diff --git "a/\320\243\321\200\320\276\320\272 7. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" "b/\320\243\321\200\320\276\320\272 7. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" index cf5789f5..72be1b2d 100644 --- "a/\320\243\321\200\320\276\320\272 7. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" +++ "b/\320\243\321\200\320\276\320\272 7. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_3.py" @@ -13,3 +13,42 @@ arr[m] from statistics import median """ +from random import randint +from statistics import median + + +# Без сортировки +def my_median(lst): + return median(lst) + + +# Сортировка +def gnome_sort(my_list): + i = 1 + j = 2 + a = my_list.copy() + while i < len(a): + if a[i - 1] > a[i]: + i = j + j = j + 1 + else: + a[i - 1], a[i] = a[i], a[i - 1] + i = i - 1 + if i == 0: + i = j + j = j + 1 + return a + + +number = int(input('Введите натуральное число: ')) +orig_list = [randint(1, 100) for _ in range(number*2+1)] +sort_list = gnome_sort(orig_list) +print(f'Оригинальный список: \n{orig_list}') +print(f'Отсортированный список: \n{sort_list}') +median_ind = len(sort_list) // 2 +sorted_median = sort_list[median_ind] +print('Медиана без сортировки: \n', my_median(orig_list)) +print(f'Медиана после сортировки: \n {sorted_median}') + + + diff --git "a/\320\243\321\200\320\276\320\272 8. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" "b/\320\243\321\200\320\276\320\272 8. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" index d46ad997..9a515783 100644 --- "a/\320\243\321\200\320\276\320\272 8. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" +++ "b/\320\243\321\200\320\276\320\272 8. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_1.py" @@ -12,3 +12,87 @@ ВНИМАНИЕ: примеры заданий будут размещены в последний день сдачи. Но постарайтесь обойтись без них. """ +from collections import Counter + + +class Haffman: + def __init__(self, string): + self.code = self.compute_code(self.get_tree(string)) + + def encode(self, string): + res = '' + for symbol in string: + res += self.code[symbol] + return res + + def decode(self, string): + res = '' + i = 0 + while i < len(string): + for el in self.code: + if string[i:].find(self.code[el]) == 0: + res += el + i += len(self.code[el]) + return res + + def get_code(self): + return self.code + + @classmethod + def compute_code(cls, root, codes=dict(), code=''): + if root is None: + return + if isinstance(root.value, str): + codes[root.value] = code + return codes + cls.compute_code(root.left, codes, code + '0') + cls.compute_code(root.right, codes, code + '1') + return codes + + @staticmethod + def get_tree(string): + string_count = Counter(string) + if len(string_count) <= 1: + node = Node(None) + if len(string_count) == 1: + node.left = Node([key for key in string_count][0]) + node.right = Node(None) + string_count = {node: 1} + while len(string_count) != 1: + node = Node(None) + tail = string_count.most_common()[:-3:-1] + if isinstance(tail[0][0], str): + node.left = Node(tail[0][0]) + else: + node.left = tail[0][0] + if isinstance(tail[1][0], str): + node.right = Node(tail[1][0]) + else: + node.right = tail[1][0] + del string_count[tail[0][0]] + del string_count[tail[1][0]] + string_count[node] = tail[0][1] + tail[1][1] + return [key for key in string_count][0] + + +class Node: + def __init__(self, value, left=None, right=None): + self.right = right + self.left = left + self.value = value + + +my_string = input('Введите строку для сжатия: ') +haffman = Haffman(my_string) +print(f'Шифр: {haffman.get_code()}') + +encoded_str = haffman.encode(my_string) +print('Сжатая строка: ', encoded_str) + +decoded_str = haffman.decode(encoded_str) +print('Исходная строка: ', decoded_str) + +if my_string == decoded_str: + print('Успешно!') +else: + print('Ошибка!') diff --git "a/\320\243\321\200\320\276\320\272 8. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" "b/\320\243\321\200\320\276\320\272 8. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" index 45e81f9c..0bfe05e3 100644 --- "a/\320\243\321\200\320\276\320\272 8. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" +++ "b/\320\243\321\200\320\276\320\272 8. \320\237\321\200\320\260\320\272\321\202\320\270\321\207\320\265\321\201\320\272\320\276\320\265 \320\267\320\260\320\264\320\260\320\275\320\270\320\265/task_2.py" @@ -10,70 +10,67 @@ Поработайте с доработанной структурой, позапускайте на реальных данных. """ + class BinaryTree: def __init__(self, root_obj): - # корень self.root = root_obj - # левый потомок self.left_child = None - # правый потомок self.right_child = None - # добавить левого потомка + def __str__(self): + return str(self.root) + def insert_left(self, new_node): - # если у узла нет левого потомка - if self.left_child == None: - # тогда узел просто вставляется в дерево - # формируется новое поддерево - self.left_child = BinaryTree(new_node) - # если у узла есть левый потомок - else: - # тогда вставляем новый узел + if new_node > self.root: + print(f'Элемент слева ({new_node}) должен быть меньше корня ({self.root})!') + return + if self.left_child: tree_obj = BinaryTree(new_node) - # и спускаем имеющегося потомка на один уровень ниже tree_obj.left_child = self.left_child self.left_child = tree_obj + else: + self.left_child = BinaryTree(new_node) - # добавить правого потомка def insert_right(self, new_node): - # если у узла нет правого потомка - if self.right_child == None: - # тогда узел просто вставляется в дерево - # формируется новое поддерево - self.right_child = BinaryTree(new_node) - # если у узла есть правый потомок - else: - # тогда вставляем новый узел + if new_node < self.root: + print(f'Элемент справа ({new_node}) должен быть больше корня ({self.root})!') + return + if self.right_child: tree_obj = BinaryTree(new_node) - # и спускаем имеющегося потомка на один уровень ниже tree_obj.right_child = self.right_child self.right_child = tree_obj + else: + self.right_child = BinaryTree(new_node) + + def get_depth(self): + depth_left = 0 if self.left_child is None else self.left_child.get_depth() + 1 + depth_right = 0 if self.right_child is None else self.right_child.get_depth() + 1 + return max(depth_left, depth_right) - # метод доступа к правому потомку def get_right_child(self): return self.right_child - # метод доступа к левому потомку def get_left_child(self): return self.left_child - # метод установки корня def set_root_val(self, obj): self.root = obj - # метод доступа к корню def get_root_val(self): return self.root -r = BinaryTree(8) +r = BinaryTree(6) print(r.get_root_val()) print(r.get_left_child()) r.insert_left(4) +r.insert_left(2) +r.insert_left(4) print(r.get_left_child()) -print(r.get_left_child().get_root_val()) +# print(r.get_left_child().get_root_val()) r.insert_right(12) print(r.get_right_child()) +# print(r.get_right_child().get_root_val()) +r.get_right_child().set_root_val(14) print(r.get_right_child().get_root_val()) -r.get_right_child().set_root_val(16) -print(r.get_right_child().get_root_val()) +print(f'Глубина дерева: {r.get_depth()}')