From 23b9b5851c29dc9ec1d0acf9d1328ed14f7e1744 Mon Sep 17 00:00:00 2001 From: Ilia Kruglov Date: Fri, 14 Sep 2018 01:49:29 +0300 Subject: [PATCH] 070_lesson --- task_01.py | 21 +++++++++++ task_02.py | 28 +++++++++++++++ task_03.py | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+) create mode 100644 task_01.py create mode 100644 task_02.py create mode 100644 task_03.py diff --git a/task_01.py b/task_01.py new file mode 100644 index 0000000..09d380b --- /dev/null +++ b/task_01.py @@ -0,0 +1,21 @@ +import random + +N = 10 + +a = [0] * N +for i in range(N): + a[i] = random.randrange(-100, 100) +print(f'raw_list = {a}') + +for i in range(N - 1): + # print('#' * 66) + # print(i) + for j in range(N - 1 - i): + # print('*' * 66) + # print(j) + if a[j] > a[j + 1]: + a[j], a[j + 1] = a[j + 1], a[j] + +print(f'sorted a = {a}') +a_reverse = sorted(a, reverse=True) +print(f'sorted and reversed = {a_reverse}') diff --git a/task_02.py b/task_02.py new file mode 100644 index 0000000..f90de72 --- /dev/null +++ b/task_02.py @@ -0,0 +1,28 @@ +import random + +N = 10 + + +def sum_(m): + s = 0 + while m > 0: + s += m % 10 + m = m // 10 + return s + + +a = [0] * N +for i in range(N): + a[i] = random.randrange(0, 50) +print(a) + +for i in range(N - 1): + for j in range(N - 1 - i): # i in first loop is 0 + if sum_(a[j]) > sum_(a[j + 1]): + a[j], a[j + 1] = a[j + 1], a[j] + +print(a) +a_result = [] +for i in range(N): + a_result.append(sum_(a[i])) +print(f'{a_result}') diff --git a/task_03.py b/task_03.py new file mode 100644 index 0000000..2881b6d --- /dev/null +++ b/task_03.py @@ -0,0 +1,102 @@ +import random + +M = 10 +N = 2 * M + 1 + +l = [0] * N +for i in range(N): + l[i] = random.randrange(0, 100) +print(f'raw_list = {l}') +x = sorted(l[:]) +print(f'sorted_list = {x}') + +# With love to https://habr.com/post/346930/ + +def nlogn_median(l): + n = len(l) + if n % 2 == 1: + return sorted(l)[n // 2] + else: + return sum(sorted(l)[n // 2 - 1: n // 2 + 1]) / 2.0 + + +def quickselect_median(l, pivot_fn=random.choice): + if len(l) % 2 == 1: + return quickselect(l, len(l) / 2, pivot_fn) + else: + return 0.5 * (quickselect(l, len(l) / 2 - 1, pivot_fn) + + quickselect(l, len(l) / 2, pivot_fn)) + + +def quickselect(l, k, pivot_fn): + """ + Выбираем k-тый элемент в списке l (с нулевой базой) + :param l: список числовых данных + :param k: индекс + :param pivot_fn: функция выбора pivot, по умолчанию выбирает случайно + :return: k-тый элемент l + """ + if len(l) == 1: + assert k == 0 + return l[0] + + pivot = pivot_fn(l) + + lows = [el for el in l if el < pivot] + highs = [el for el in l if el > pivot] + pivots = [el for el in l if el == pivot] + + if k < len(lows): + return quickselect(lows, k, pivot_fn) + elif k < len(lows) + len(pivots): + # Нам повезло и мы угадали медиану + return pivots[0] + else: + return quickselect(highs, k - len(lows) - len(pivots), pivot_fn) + + +def pick_pivot(l): + """ + Выбираем хорошй pivot в списке чисел l + Этот алгоритм выполняется за время O(n). + """ + assert len(l) > 0 + + # Если элементов < 5, просто возвращаем медиану + if len(l) < 5: + # В этом случае мы возвращаемся к первой написанной нами функции медианы. + # Поскольку мы выполняем её только для списка из пяти или менее элементов, она не + # зависит от длины входных данных и может считаться постоянным + # временем. + return nlogn_median(l) + + # Сначала разделим l на группы по 5 элементов. O(n) + chunks = chunked(l, 5) + + # Для простоты мы можем отбросить все группы, которые не являются полными. O(n) + full_chunks = [chunk for chunk in chunks if len(chunk) == 5] + + # Затем мы сортируем каждый фрагмент. Каждая группа имеет фиксированную длину, поэтому каждая сортировка + # занимает постоянное время. Поскольку у нас есть n/5 фрагментов, эта операция + # тоже O(n) + sorted_groups = [sorted(chunk) for chunk in full_chunks] + + # Медиана каждого фрагмента имеет индекс 2 + medians = [chunk[2] for chunk in sorted_groups] + + # Возможно, я немного повторюсь, но я собираюсь доказать, что нахождение + # медианы списка можно произвести за доказуемое O(n). + # Мы находим медиану списка длиной n/5, поэтому эта операция также O(n) + # Мы передаём нашу текущую функцию pick_pivot в качестве создателя pivot алгоритму + # quickselect. O(n) + median_of_medians = quickselect_median(medians, pick_pivot) + return median_of_medians + + +def chunked(l, chunk_size): + """Разделяем список `l` на фрагменты размером `chunk_size`.""" + return [l[i:i + chunk_size] for i in range(0, len(l), chunk_size)] + +print(f'n*logn median = {nlogn_median(l)}') +print(f'quickselect_median = {quickselect_median(l, pivot_fn=random.choice)}') +print(f'determine O(n) = {pick_pivot(l)}') # что-то здесь пошло не так с медианой???