From a82d83691065a34672387208d9511753d77500ff Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 06:38:54 +0300 Subject: [PATCH 01/30] lab 1 --- lab1/Vasich/Hello world | 1 + 1 file changed, 1 insertion(+) create mode 100644 lab1/Vasich/Hello world diff --git a/lab1/Vasich/Hello world b/lab1/Vasich/Hello world new file mode 100644 index 0000000..57cf853 --- /dev/null +++ b/lab1/Vasich/Hello world @@ -0,0 +1 @@ +here we are From 62daa7eb6a30353e621314eccb0eacd1abd78e91 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 06:40:52 +0300 Subject: [PATCH 02/30] lab 2 done --- lab2/Vasich/sieve_of_eratosthenes.py | 154 +++++++++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 lab2/Vasich/sieve_of_eratosthenes.py diff --git a/lab2/Vasich/sieve_of_eratosthenes.py b/lab2/Vasich/sieve_of_eratosthenes.py new file mode 100644 index 0000000..64e39ca --- /dev/null +++ b/lab2/Vasich/sieve_of_eratosthenes.py @@ -0,0 +1,154 @@ +class Set: + def add(self, value): + pass + + def __iter__(self): + pass + + +class SplayTree(Set): + class Node: + def __init__(self, value, left=None, right=None, parent=None): + self.value = value + self.left = left + if left is not None: + left.parent = self + self.right = right + if right is not None: + right.parent = self + self.parent = parent + + def add_left(self, value): + self.left = SplayTree.Node(value, None, None, self) + + def set_left(self, node): + self.left = node + if node is not None: + node.parent = self + + def add_right(self, value): + self.right = SplayTree.Node(value, None, None, self) + + def set_right(self, node): + self.right = node + if node is not None: + node.parent = self + + def __init__(self): + self._root = None + + def _rotate(self, node): + parent = node.parent + g_parent = parent.parent + + if g_parent is not None: + if g_parent.left == parent: + g_parent.set_left(node) + else: + g_parent.set_right(node) + + node.parent = g_parent + + if parent.left == node: + parent.set_left(node.right) + node.set_right(parent) + else: + parent.set_right(node.left) + node.set_left(parent) + + def _splay(self, node): + parent = node.parent + + while parent is not None: + g_parent = parent.parent + if g_parent is not None: + if g_parent.left is parent == parent.left is node: + self._rotate(parent) + else: + self._rotate(node) + + self._rotate(node) + parent = node.parent + + self._root = node + return node + + def _find(self, value, sub_tree): + if sub_tree is None: + return None + elif value < sub_tree.value and sub_tree.left is not None: + return self._find(value, sub_tree.left) + elif value > sub_tree.value and sub_tree.right is not None: + return self._find(value, sub_tree.right) + else: + return sub_tree + + def find(self, value): + if self._root is None: + return None + else: + node = self._find(value, self._root) + if node.value == value: + self._splay(node) + return node + else: + return None + + def contains(self, value): + return self.find(value) is not None + + def split(self, value): + node = self._find(value, self._root) + + if node is None: + return None, None + + self._splay(node) + + if node.value <= value: + right = node.right + node.right = None + return node, right + else: + left = node.left + node.left = None + return left, node + + def merge(self, left, right): + if left is None: + return right + + while left.right is not None: + left = left.right + + self._splay(left) + left.set_right(right) + + def add(self, value): + left, right = self.split(value) + self._root = SplayTree.Node(value, left, right) + + def remove(self, value): + node = self.find(value) + + while node is not None: + if node.left is not None: + node.left.parent = None + if node.right is not None: + node.right.parent = None + self.merge(node.left, node.right) + node = self.find(value) + + def iterate(self, node): + if node.left is not None: + yield from self.iterate(node.left) + yield node.value + if node.right is not None: + yield from self.iterate(node.right) + + def __iter__(self): + self.rec_depth = 0 + if self._root is None: + return iter([]) + else: + return self.iterate(self._root) From f77f83e95c457e319bd93e82ad0c4cd2140ffdec Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 06:46:16 +0300 Subject: [PATCH 03/30] lab 3 --- lab3/Vasich/money_change.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 lab3/Vasich/money_change.py diff --git a/lab3/Vasich/money_change.py b/lab3/Vasich/money_change.py new file mode 100644 index 0000000..4b7f6c2 --- /dev/null +++ b/lab3/Vasich/money_change.py @@ -0,0 +1,16 @@ +from sys import stdin + +_cash = int(stdin.readline()) +second_line = stdin.readline() +coins = [int(c) for c in second_line.split(' ')] + + +def way_count(cash, coin_index): + if cash == 0: + return 1 + elif cash < 0 or coin_index == 0: + return 0 + return way_count(cash - coins[coin_index - 1], coin_index) + way_count(cash, coin_index - 1) + + +print(way_count(_cash, len(coins))) From d9e7a4d4b77d5c3f141bb8f174c9778eef3c77fe Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 07:09:31 +0300 Subject: [PATCH 04/30] b4 lab4 --- .../__pycache__/combine_sort.cpython-35.pyc | Bin 0 -> 1551 bytes lab4/Vasich/combine_sort.py | 51 ++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 lab4/Vasich/__pycache__/combine_sort.cpython-35.pyc create mode 100644 lab4/Vasich/combine_sort.py diff --git a/lab4/Vasich/__pycache__/combine_sort.cpython-35.pyc b/lab4/Vasich/__pycache__/combine_sort.cpython-35.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cffb0108432b7e166c0b35b0ba9311b6f823676e GIT binary patch literal 1551 zcmZ8hON$#v5U%cdNTZj<#_X=v2Ky8kaEvz?9E@TDHsqAW;KTtT$BZ>?X`~rFdd5To z2|_kMAo&S7=8#)*%a2%J`Uk8q6npdwQO~CsU&YQV6jvz@ z?7T`!&^VxT?5RhLCZB2L~Fr89<3#vOM3Qd zNE?UNU^~>=xcr0kc;nHsOKXHFY2uMi?G}$ZYnLYO^))oH3kP<~{})hQoYME$$fxdP zi<{sO0&vc@0VSbf`k#IJsJIP?0W-qo%PDW8+NJ%829-(k<-%?`x2!kNe-{ zO6UEHU*G@q{^yIoFaGI2Ukyf)&YtVpSPhE2pUvWTsXFba(VK_;mrwKn*`}37)B~u(zB(teyRdICQ1|e}GYIyI61JT0J%pABZ!BfZBXEZf6 z&fAb^<6Byx&m4r zOb3^`DRix1rwfa)!!)4f4?ENWt@Ys>+SJ$wnC?Ier*tMjWV`3Vu^M$D2KbL~&f+gN z%lp`876qj!V9_P67E;Yc7do2T%J|WI4k$IJFRW`$vJR{uOX4_Hy2cBcoML=#+*G|S zP!P#*ROlw}<#Zb{vFMlN26Mbj>7n`r)BIBqvVi%*mxrPwn!-|vHD)&fVpFz6OX_3n z+_wgMvqE)o6XSl^42KS+m*F2T=YfA^H}0pJC+OCM4Pjx{dcx zwxyK~xY_t&%N)AB5pH9GT7_4y4rn8GMS{xvP13@r7uHI7u@ty)%w-@)&LxO*11(b%h8Gh6e$WZWz&Mz$jK2{XCB%6K^nQ`IVpQ*HCvej!gWV|1BQYai+Xyc@6dd(jWUfTkxcFQZ^3CC^Q`cSkT-)YnvCyho! H+!p@>mKh`t literal 0 HcmV?d00001 diff --git a/lab4/Vasich/combine_sort.py b/lab4/Vasich/combine_sort.py new file mode 100644 index 0000000..a424542 --- /dev/null +++ b/lab4/Vasich/combine_sort.py @@ -0,0 +1,51 @@ +from math import inf + +insertion_max = 24 + + +def insertion_sort(seq, start, end): + for j in range(start + 1, end): + key = seq[j] + i = j - 1 + while i >= start and seq[i] > key: + seq[i + 1] = seq[i] + i -= 1 + seq[i + 1] = key + return seq + + +def merge(seq, start, middle, end): + i1 = middle - start + i2 = end - middle + left = [] + right = [] + + for i in range(0, i1): + left.append(seq[start + i]) + left.append(inf) + for j in range(0, i2): + right.append(seq[middle + j]) + right.append(inf) + + i = 0 + j = 0 + for k in range(start, end): + if left[i] < right[j]: + seq[k] = left[i] + i += 1 + else: + seq[k] = right[j] + j += 1 + + return seq + + +def merge_sort(seq, start, end): + if end - start > insertion_max: + middle = (start + end) // 2 + merge_sort(seq, start, middle) + merge_sort(seq, middle, end) + merge(seq, start, middle, end) + else: + insertion_sort(seq, start, end) + return seq From aa39bdf3fd52c1a7da053b82e4b01b33b86e6d15 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 07:13:35 +0300 Subject: [PATCH 05/30] lab 5 --- lab5/Vasich/quicksort.py | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 lab5/Vasich/quicksort.py diff --git a/lab5/Vasich/quicksort.py b/lab5/Vasich/quicksort.py new file mode 100644 index 0000000..e9b0561 --- /dev/null +++ b/lab5/Vasich/quicksort.py @@ -0,0 +1,30 @@ +import random + + +def partition(seq, start, end): + p = random.randint(start, end - 1) + seq[p], seq[end - 1] = seq[end - 1], seq[p] + pivot = seq[end - 1] + + lower_mid = j = start + upper_mid = end - 1 + while j <= upper_mid: + if seq[j] < pivot: + seq[lower_mid], seq[j] = seq[j], seq[lower_mid] + lower_mid += 1 + j += 1 + elif seq[j] > pivot: + seq[upper_mid], seq[j] = seq[j], seq[upper_mid] + upper_mid -= 1 + else: + j += 1 + + return lower_mid, upper_mid + + +def quicksort(seq, start, end): + if start < end - 1: + lower_mid, upper_mid = partition(seq, start, end) + quicksort(seq, start, lower_mid) + quicksort(seq, upper_mid + 1, end) + return seq From a74f790bd0e8b51df903c3f959d16c53d0927738 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 07:13:55 +0300 Subject: [PATCH 06/30] lab 6 --- lab6/Vasich/radix_sort.py | 35 ++++++++++++++++++++ lab6/Vasich/tests.py | 70 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 lab6/Vasich/radix_sort.py create mode 100644 lab6/Vasich/tests.py diff --git a/lab6/Vasich/radix_sort.py b/lab6/Vasich/radix_sort.py new file mode 100644 index 0000000..40d7690 --- /dev/null +++ b/lab6/Vasich/radix_sort.py @@ -0,0 +1,35 @@ +radix = 10 + + +def radix_sort(seq): + p = 0 + done = False + while done is False: + done = True + digits = [[] for _ in range(0, radix)] + for i in range(0, len(seq)): + div = (seq[i] // (radix ** p)) + if div != 0 and div != -1: + done = False + digits[div % radix].append(seq[i]) + j = 0 + for d in range(0, radix): + digit = digits[d] + for k in range(0, len(digit)): + seq[j] = digit[k] + j += 1 + p += 1 + + signs = [[] for _ in range(0, 2)] + for i in range(0, len(seq)): + if seq[i] < 0: + signs[0].append(seq[i]) + else: + signs[1].append(seq[i]) + j = 0 + for s in range(0, 2): + sign = signs[s] + for k in range(0, len(sign)): + seq[j] = sign[k] + j += 1 + return seq diff --git a/lab6/Vasich/tests.py b/lab6/Vasich/tests.py new file mode 100644 index 0000000..bf4f0f4 --- /dev/null +++ b/lab6/Vasich/tests.py @@ -0,0 +1,70 @@ +from random import randint +from lab6.Vasich.radix_sort import radix_sort +import unittest + + +class TestSorting(unittest.TestCase): + + def _check(self, seq): + if len(seq) <= 1: + return True + i = 1 + while i < len(seq): + if seq[i - 1] > seq[i]: + return False + i += 1 + + return True + + def test_trivial(self): + seq = [1, 333, 22] + res = radix_sort(seq) + expected = [1, 22, 333] + + self.assertEqual(expected, res) + + def test_empty(self): + seq = [] + res = radix_sort(seq) + expected = [] + self.assertEqual(expected, res) + + def test_ascending(self): + size = 100000 + seq = [0] * size + for i in range(1, size): + seq[i] = seq[i - 1] + randint(1, 10) + radix_sort(seq) + self.assertTrue(self._check(seq)) + + def test_repeating_ascending(self): + size = 100000 + seq = [0] * size + for i in range(1, size): + seq[i] = seq[i - 1] + randint(0, 4) + radix_sort(seq) + self.assertTrue(self._check(seq)) + + def test_descending(self): + size = 100000 + seq = [randint(0, size)] * size + for i in range(size): + seq[i] = seq[i - 1] - randint(1, 10) + radix_sort(seq) + self.assertTrue(self._check(seq)) + + def test_positive_random(self): + size = 100000 + seq = [0] * size + for i in range(size): + seq[i] = randint(0, 100000) + radix_sort(seq) + self.assertTrue(self._check(seq)) + + def test_positive_and_negative_random(self): + size = 100000 + seq = [0] * size + for i in range(size): + seq[i] = randint(-100000, 100000) + radix_sort(seq) + self.assertTrue(self._check(seq)) From de6ac3dfafdfcbc598582659dcf2bb7006516196 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 07:14:06 +0300 Subject: [PATCH 07/30] lab 7 --- .../__pycache__/generators.cpython-35.pyc | Bin 0 -> 1349 bytes lab7/Vasich/comparison.py | 56 ++++++++++++++++++ lab7/Vasich/generators.py | 50 ++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 lab7/Vasich/__pycache__/generators.cpython-35.pyc create mode 100644 lab7/Vasich/comparison.py create mode 100644 lab7/Vasich/generators.py diff --git a/lab7/Vasich/__pycache__/generators.cpython-35.pyc b/lab7/Vasich/__pycache__/generators.cpython-35.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6357e157c9fa0a4173f1a72873d14c53ba3b39c GIT binary patch literal 1349 zcmbtU&1w@-6h3!mGWqGGt+h>R7ve&Y5foiWQG$p?x+{fZg)mUZ%r!}yN$kDppG-ik z58xXJ?tB1ug0IkST#QRseE`?`ojYkrLl=UVxhLP;oO|v$-*?Yc%H`7Qoz=}bhv*lL z4GZ`Qre24M@CfP<#e(XBL}XE9(+8qDfJ0HvV4EVBqP)RaEKpQ5I7d;5qA7#n;L(O( zK0{RUMVeP(H)?nL4VxD*a+r))F!d@74sHrcESewS06_zX4)0Ln@X`*EdP;qw1dpI& zixQjvs$n9>W%%w^=mi!xe0xm^ggay73&r*Mxzz6T4pOJpZnjcKx8KUt)^ax$?JuN? z@c8`SSh7ZK+v!jD+Ddcp71D0F3IzjXbsq*A!K6<2piJ zpbcNF`IZqEdE#{6xvZ4QY%8H|NbZg1g_LjNK+W}&m_veU4(NYV;~3~fxsOXO|1G;} zBri?xHbRZ3H$RykD{Pos0vIue%azeKY<0ugut_J`s@vVYc#^GI9mX<~J(KnxC&Drj zx=StKcg@eIZq|gR`;8(-T0^4ZRE^_UZ2kr)b9oB2ti>Pm_e1m2tnC%Os^@y{Up;U0 A$^ZZW literal 0 HcmV?d00001 diff --git a/lab7/Vasich/comparison.py b/lab7/Vasich/comparison.py new file mode 100644 index 0000000..0e948ef --- /dev/null +++ b/lab7/Vasich/comparison.py @@ -0,0 +1,56 @@ +from lab4.Vasich.combine_sort import merge_sort +from lab5.Vasich.quicksort import quicksort +from lab6.Vasich.radix_sort import radix_sort +from lab7.Vasich.generators import * +from time import time +import pylab + + +# almost completely stolen from vks +def grade(sort_func, array_generator, size): + millis = 0.0 + for i in range(5): + array = array_generator(size) + t1 = time() + sort_func(array) + t2 = time() + millis += t2 - t1 + millis /= 5.0 + return millis + + +funcs = dict() +funcs["Combined sort"] = lambda x: merge_sort(x, 0, len(x)) +funcs["Quick sort"] = lambda x: quicksort(x, 0, len(x)) +funcs["Radix sort"] = lambda x: radix_sort(x) +funcs["Standard sort"] = sorted + + +arrs = dict() +arrs["Random array (-1000000 to 1000000)"] = lambda x: random_array(-1000000, 1000001, x) +arrs["Random array (0 to 10000)"] = lambda x: random_array(0, 10001, x) +arrs["Semi-sorted array (0 to 10000)"] = lambda x: semi_sorted_array(0, 10001, x) +arrs["Ascending sorted array (0 to 10000)"] = lambda x: ascending_sorted_array(0, 10001, x) +arrs["Descending sorted array (0 to 10000)"] = lambda x: descending_sorted_array(0, 10001, x) +arrs["Array of repeating values"] = lambda x: same_value_array(-100000, 100001, x) + +sizes = [100 + 100000 * i for i in range(6)] +current = 1 + +for gen_name, gen in arrs.items(): + pylab.subplot(2, 3, current) + pylab.xlabel("size, elements") + pylab.ylabel("time, sec") + print("Now passing: %s" % gen_name) + for func_name, func in funcs.items(): + millis = [] + for size in sizes: + print("\tUsing %s on array of size %s" % (func_name, size)) + millis.append(grade(func, gen, size)) + print("\n\t***\n") + pylab.plot(sizes, millis, label=func_name) + pylab.title(gen_name) + pylab.legend(loc='upper left', title="Sorts") + current += 1 + +pylab.show() diff --git a/lab7/Vasich/generators.py b/lab7/Vasich/generators.py new file mode 100644 index 0000000..abe265d --- /dev/null +++ b/lab7/Vasich/generators.py @@ -0,0 +1,50 @@ +from random import randint + + +def random_array(low, high, size): + seq = [0] * size + i = 0 + while i < size: + seq[i] = randint(low, high) + i += 1 + return seq + + +def semi_sorted_array(low, high, size): + + seq = [0] * size + + value = randint(low, high) + seq[0] = value + + sign = 1 + i = 1 + while i < size: + if randint(0, 10) == 0: + sign *= -1 + new_value = seq[i - 1] + sign * randint(0, 1 + high // 10) + if new_value >= high or new_value < low: + sign *= -1 + seq[i] = randint(low, high) + else: + seq[i] = new_value + i += 1 + + return seq + + +def ascending_sorted_array(low, high, size): + seq = random_array(low, high, size) + seq.sort() + return seq + + +def descending_sorted_array(low, high, size): + seq = ascending_sorted_array(low, high, size) + seq.reverse() + return seq + + +def same_value_array(low, high, size): + num = randint(low, high) + return [num] * size From cdea930cc445ebab35f82dcaa628dc26687e138a Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 07:14:19 +0300 Subject: [PATCH 08/30] lab 8 --- lab8/Vasich/queue.py | 86 ++++++++++++++++++++++++++++++++++++++++++++ lab8/Vasich/tests.py | 40 +++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 lab8/Vasich/queue.py create mode 100644 lab8/Vasich/tests.py diff --git a/lab8/Vasich/queue.py b/lab8/Vasich/queue.py new file mode 100644 index 0000000..1eef831 --- /dev/null +++ b/lab8/Vasich/queue.py @@ -0,0 +1,86 @@ +from sys import stdin, stdout + + +class Queue: + def pop(self): + pass + + def push(self, n): + pass + + def size(self): + pass + + +# implement Queue +class StacksQueue(Queue): + def __init__(self): + self._seq = [] + + def push(self, a): + self._seq.append(a) + + def pop(self): + if self.size() > 0: + return self._seq.pop() + else: + return None + + def size(self): + return len(self._seq) + + +class MaxElementQueue(Queue): + def __init__(self): + self._maxes = [float("-inf")] + self._push_max = float("-inf") + self._pop = StacksQueue() + self._push = StacksQueue() + + def pop(self): + if self._pop.size() == 0: + element = self._push.pop() + while element is not None: + self._pop.push(element) + self._maxes.append(max(element, self._maxes[len(self._maxes) - 1])) + element = self._push.pop() + self._push_max = float("-inf") + value = self._pop.pop() + if value is not None: + self._maxes.pop() + return value + else: + return "empty" + + def push(self, n): + self._push.push(n) + self._push_max = max(self._push_max, n) + + def size(self): + return self._push.size() + self._pop.size() + + def max(self): + value = max(self._push_max, self._maxes[len(self._maxes) - 1]) + if value != float("-inf"): + return value + else: + return "empty" + + +def parse_line(string, max_element_queue): + string = string.split("\n")[0] + if string == "max": + return str(max_element_queue.max()) + elif string == "pop": + return str(max_element_queue.pop()) + else: + command = string.split() + if len(command) == 2 and command[0] == "push": + max_element_queue.push(int(command[1])) + return "ok" + return "unknown command" + +if __name__ == "__main__": + queue = MaxElementQueue() + for line in stdin: + print(parse_line(line, queue)) diff --git a/lab8/Vasich/tests.py b/lab8/Vasich/tests.py new file mode 100644 index 0000000..97465f1 --- /dev/null +++ b/lab8/Vasich/tests.py @@ -0,0 +1,40 @@ +from lab8.Vasich.queue import parse_line, MaxElementQueue +from random import randint +import unittest + + +class TestQueue(unittest.TestCase): + def _check(self, commands, expected_out, queue): + size = len(commands) + for i in range(size): + self.assertEqual(expected_out[i], parse_line(commands[i], queue)) + + def test_empty(self): + queue = MaxElementQueue() + strings = ["max", "max", "pop"] + ans = ["empty", "empty", "empty"] + self._check(strings, ans, queue) + + def test_pops(self): + queue = MaxElementQueue() + self.assertEqual("empty", queue.pop()) + + count = 500 + first = randint(-100, 100) + queue.push(first) + for _ in range(count): + queue.push(randint(-100, 100)) + self.assertEqual(first, queue.pop()) + + for _ in range(count): + queue.pop() + self.assertEqual("empty", queue.pop()) + + def test_manual(self): + queue = MaxElementQueue() + strings = ["push 3", "push 14", "push 15", "push 3", "push 14", "push 15", "max", "push 28", "push 18", + "push 7", "push 2", "pop", "pop", "pop", "max", "push 42", "max", "pop", "max", "pop", "pop", "pop", + "pop", "pop", "max", "pop", "pop", "max", "pop", "pop", "push 30", "max", "pop"] + ans = ["ok", "ok", "ok", "ok", "ok", "ok", "15", "ok", "ok", "ok", "ok", "3", "14", "15", "28", "ok", "42", "3", + "42", "14", "15", "28", "18", "7", "42", "2", "42", "empty", "empty", "empty", "ok", "30", "30"] + self._check(strings, ans, queue) From fee3df747ef60d481c4a201745ae603ff6248d11 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 07:14:29 +0300 Subject: [PATCH 09/30] lab 9 --- lab9/Vasich/k_max_p1.py | 71 +++++++++++++++++++++++++++++++++++++++++ lab9/Vasich/k_max_p2.py | 52 ++++++++++++++++++++++++++++++ lab9/Vasich/tests.py | 53 ++++++++++++++++++++++++++++++ 3 files changed, 176 insertions(+) create mode 100644 lab9/Vasich/k_max_p1.py create mode 100644 lab9/Vasich/k_max_p2.py create mode 100644 lab9/Vasich/tests.py diff --git a/lab9/Vasich/k_max_p1.py b/lab9/Vasich/k_max_p1.py new file mode 100644 index 0000000..8f2568f --- /dev/null +++ b/lab9/Vasich/k_max_p1.py @@ -0,0 +1,71 @@ +class Queue: + def pop(self): + pass + + def push(self, n): + pass + + def size(self): + pass + + +class MinHeap(Queue): + def __init__(self, k): + self._size = 0 + self._k = k + self._seq = [] + + def pop(self): + if self._size > 0: + self._seq[0], self._seq[self._size - 1] = self._seq[self._size - 1], self._seq[0] + value = self._seq.pop() + self._size -= 1 + + i = 0 + while i < self._size: + left = float("inf") + right = float("inf") + + if 2 * i + 1 < self._size: + left = self._seq[2 * i + 1] + if 2 * i + 2 < self._size: + right = self._seq[2 * i + 2] + + if left < right: + m = left + i_m = 2 * i + 1 + else: + m = right + i_m = 2 * i + 2 + + if self._seq[i] > m: + self._seq[i], self._seq[i_m] = self._seq[i_m], self._seq[i] + i = i_m + else: + break + + return value + + else: + return "empty" + + def push(self, n): + self._seq.append(n) + self._size += 1 + + i = self._size - 1 + while i > 0: + if self._seq[(i - 1) // 2] > self._seq[i]: + self._seq[(i - 1) // 2], self._seq[i] = self._seq[i], self._seq[(i - 1) // 2] + i = (i - 1) // 2 + else: + break + + if self._size > self._k: + self.pop() + + def size(self): + return self._size + + def max_list(self): + return self._seq diff --git a/lab9/Vasich/k_max_p2.py b/lab9/Vasich/k_max_p2.py new file mode 100644 index 0000000..9aa7fa2 --- /dev/null +++ b/lab9/Vasich/k_max_p2.py @@ -0,0 +1,52 @@ +from sys import stdin, stdout + + +def find_pivot(seq, start, end, sub_length): + medians = [] + sub_seq = [] + while end - start > sub_length: + for i in range(start, start + sub_length): + sub_seq.append(seq[i]) + sub_seq.sort() + medians.append(sub_seq[2]) + start += sub_length + sub_seq = [] + + for i in range(start, end): + sub_seq.append(seq[i]) + sub_seq.sort() + medians.append(sub_seq[len(sub_seq) // 2]) + + medians.sort() + return medians[len(medians) // 2] + + +def partition(seq, start, end): + pivot = find_pivot(seq, start, end, 5) + + lower_mid = j = start + upper_mid = end - 1 + while j <= upper_mid: + if seq[j] > pivot: + seq[lower_mid], seq[j] = seq[j], seq[lower_mid] + lower_mid += 1 + j += 1 + elif seq[j] < pivot: + seq[upper_mid], seq[j] = seq[j], seq[upper_mid] + upper_mid -= 1 + else: + j += 1 + + return lower_mid, upper_mid + + +def quickselect(seq, start, end, k): + if start < end - 1: + lower_mid, upper_mid = partition(seq, start, end) + if k < lower_mid: + return quickselect(seq, start, lower_mid, k) + if k >= upper_mid: + return quickselect(seq, upper_mid + 1, end, k) + return seq[0:min(k, len(seq))] + + diff --git a/lab9/Vasich/tests.py b/lab9/Vasich/tests.py new file mode 100644 index 0000000..37f9b05 --- /dev/null +++ b/lab9/Vasich/tests.py @@ -0,0 +1,53 @@ +from lab9.Vasich.k_max_p1 import MinHeap +from lab9.Vasich.k_max_p2 import quickselect +from random import randint +import unittest + + +class TestMax(unittest.TestCase): + def _check(self, input_arr, out_arr): + input_arr.sort() + answer = [input_arr[i] for i in range(len(input_arr) - len(out_arr), len(input_arr))] + result = [out_arr[i] for i in range(len(out_arr))] + + result.sort() + + for i in range(0, len(result)): + if answer[i] != result[i]: + return False + return True + + def test_random(self): + size = 1000 + k = 20 + input_arr = [0] * size + for i in range(size): + input_arr[i] = randint(-1000, 1000) + mh = MinHeap(20) + for i in range(size): + mh.push(input_arr[i]) + output_arr1 = mh.max_list() + output_arr2 = quickselect(input_arr, 0, len(input_arr), k) + + self.assertTrue(self._check(input_arr, output_arr1)) + self.assertTrue(self._check(input_arr, output_arr2)) + + def test_max(self): + max_val = float("-inf") + size = 1000 + k = 1 + input_arr = [0] * size + + for i in range(size): + input_arr[i] = randint(-1000, 1000) + if input_arr[i] > max_val: + max_val = input_arr[i] + + mh = MinHeap(k) + for i in range(size): + mh.push(input_arr[i]) + output_arr1 = mh.max_list() + output_arr2 = quickselect(input_arr, 0, len(input_arr), k) + + self.assertEqual(max_val, output_arr1[0]) + self.assertEqual(max_val, output_arr2[0]) From ebecece479e31290f60e3dca441eeb3c801e8eb7 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 07:14:41 +0300 Subject: [PATCH 10/30] lab 10 --- lab10/Vasich/pythagorean_triples.py | 37 ++++++++++++++++++++++ lab10/Vasich/tests.py | 49 +++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 lab10/Vasich/pythagorean_triples.py create mode 100644 lab10/Vasich/tests.py diff --git a/lab10/Vasich/pythagorean_triples.py b/lab10/Vasich/pythagorean_triples.py new file mode 100644 index 0000000..d62bc3d --- /dev/null +++ b/lab10/Vasich/pythagorean_triples.py @@ -0,0 +1,37 @@ +from sys import stdin, stdout + + +def triples(seq): + # n log(n) + seq.sort() + + arr = [seq[0] ** 2] + + j = 0 + + # n + for i in range(1, len(seq)): + value = seq[i] ** 2 + if arr[j] != value: + arr.append(value) + j += 1 + + if len(arr) < 3: + return 0 + + count = 0 + # n^2 (3SUM) + for i in range(2, len(arr)): + start = 0 + end = i - 1 + while start < end: + if arr[start] + arr[end] == arr[i]: + count += 1 + start += 1 + end -= 1 + elif arr[start] + arr[end] > arr[i]: + end -= 1 + else: + start += 1 + + return count diff --git a/lab10/Vasich/tests.py b/lab10/Vasich/tests.py new file mode 100644 index 0000000..88cd939 --- /dev/null +++ b/lab10/Vasich/tests.py @@ -0,0 +1,49 @@ +from lab10.Vasich.pythagorean_triples import triples +from random import randint + +import unittest + + +class TestTriples(unittest.TestCase): + def _check(self, input_arr, out_value): + work_copy = [input_arr[i] ** 2 for i in range(len(input_arr))] + work_copy.sort() + arr = [work_copy[0]] + + j = 0 + for i in range(1, len(work_copy)): + value = work_copy[i] + if arr[j] != value: + arr.append(value) + j += 1 + + count = 0 + for i in range(len(arr) - 1, -1, -1): + for j in range(i - 1, -1, -1): + for k in range(j - 1, -1, -1): + if arr[i] == arr[j] + arr[k]: + count += 1 + return count == out_value + + def test_egypt(self): + input_arr = [3, 4, 5] + self.assertEqual(1, triples(input_arr)) + + def test_manual1(self): + input_arr = [20, 21, 29, 12, 16, 3] + self.assertEqual(2, triples(input_arr)) + + def test_manual2(self): + input_arr = [23, 247, 19, 96, 264, 265, 132, 181] + self.assertEqual(2, triples(input_arr)) + + def test_manual3(self): + input_arr = [12, 15, 24, 27, 40, 1, 42] + self.assertEqual(0, triples(input_arr)) + + def test_random(self): + size = 500 + input_arr = [0] * size + for i in range(size): + input_arr[i] = randint(0, 1000) + self.assertTrue(self._check(input_arr, triples(input_arr))) From 706d88ca79ce00ee67005ee401b63a2af6947c00 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 07:14:51 +0300 Subject: [PATCH 11/30] lab 11 --- lab11/Vasich/bar_chart.py | 33 +++++++++++++++++++++++++++++++++ lab11/Vasich/tests.py | 23 +++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100644 lab11/Vasich/bar_chart.py create mode 100644 lab11/Vasich/tests.py diff --git a/lab11/Vasich/bar_chart.py b/lab11/Vasich/bar_chart.py new file mode 100644 index 0000000..3561ba7 --- /dev/null +++ b/lab11/Vasich/bar_chart.py @@ -0,0 +1,33 @@ + +def chart_area(seq): + if len(seq) < 3: + return 0 + + max_sum = float("-inf") + + height = seq[0] + curr_sum = 0 + + for i in range(1, len(seq)): + if seq[i] < height: + curr_sum += height - seq[i] + else: + if curr_sum >= max_sum: + max_sum = curr_sum + height = seq[i] + curr_sum = 0 + + height = seq[len(seq) - 1] + curr_sum = 0 + + for i in range(len(seq) - 2, -1, -1): + if seq[i] < height: + curr_sum += height - seq[i] + else: + if curr_sum >= max_sum: + max_sum = curr_sum + height = seq[i] + curr_sum = 0 + + return max_sum + diff --git a/lab11/Vasich/tests.py b/lab11/Vasich/tests.py new file mode 100644 index 0000000..ec7de79 --- /dev/null +++ b/lab11/Vasich/tests.py @@ -0,0 +1,23 @@ +from lab11.Vasich.bar_chart import chart_area + +import unittest + + +class TestBarChart(unittest.TestCase): + def test_empty_chart(self): + self.assertEqual(0, chart_area([])) + + def test_plane(self): + self.assertEqual(0, chart_area([2, 2, 2, 2, 2])) + + def test_ascending(self): + self.assertEqual(0, chart_area([2, 3, 5, 8, 11])) + + def test_descending(self): + self.assertEqual(0, chart_area([52, 43, 35, 28, 11])) + + def test_castle_wall(self): + self.assertEqual(1, chart_area([1, 2, 1, 2, 1, 2, 1, 2])) + + def test_mount_elbrus(self): + self.assertEqual(25, chart_area([1, 2, 4, 8, 16, 6, 6, 8, 15, 7, 6, 7, 0])) From ccfd491374f5ac42801e3d4aaec711f50f9a575a Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 07:15:02 +0300 Subject: [PATCH 12/30] lab 12 --- lab12/Vasich/tets.py | 76 +++++++++++++++++++++++++++++++++++++ lab12/Vasich/tree.py | 90 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 lab12/Vasich/tets.py create mode 100644 lab12/Vasich/tree.py diff --git a/lab12/Vasich/tets.py b/lab12/Vasich/tets.py new file mode 100644 index 0000000..5ead323 --- /dev/null +++ b/lab12/Vasich/tets.py @@ -0,0 +1,76 @@ +from lab12.Vasich.tree import UnbalancedBinarySearchTree +from random import randint +import unittest + + +class TestQueue(unittest.TestCase): + def _check(self, input_arr): + tree = UnbalancedBinarySearchTree() + + for v in input_arr: + tree.add(v) + + input_arr.sort() + i = 0 + for p in tree: + if p != input_arr[i]: + return False + i += 1 + return True + + def test_empty(self): + self.assertTrue(self._check([])) + + def test_ascending(self): + size = 100 + input_arr = [0] * size + for i in range(1, size): + input_arr[i] = input_arr[i - 1] + randint(1, 10) + self.assertTrue(self._check(input_arr)) + + def test_repeating_ascending(self): + size = 100 + input_arr = [0] * size + for i in range(size): + input_arr[i] = input_arr[i - 1] + randint(0, 4) + self.assertTrue(self._check(input_arr)) + + def test_descending(self): + size = 100 + input_arr = [randint(0, size)] * size + for i in range(size): + input_arr[i] = input_arr[i - 1] - randint(1, 10) + self.assertTrue(self._check(input_arr)) + + def test_random(self): + size = 100 + input_arr = [0] * size + for i in range(size): + input_arr[i] = randint(-1000, 1000) + self.assertTrue(self._check(input_arr)) + + def test_contains(self): + size = 100 + input_arr = [0] * size + for i in range(size): + input_arr[i] = randint(-1000, 1000) + + tree = UnbalancedBinarySearchTree() + for v in input_arr: + tree.add(v) + + value = input_arr[randint(0, size)] + self.assertTrue(tree.contains(value)) + + def test_contains1(self): + size = 100 + input_arr = [0] * size + for i in range(size): + input_arr[i] = randint(-1000, 1000) + + tree = UnbalancedBinarySearchTree() + for v in input_arr: + tree.add(v) + + value = 1001 + self.assertFalse(tree.contains(value)) \ No newline at end of file diff --git a/lab12/Vasich/tree.py b/lab12/Vasich/tree.py new file mode 100644 index 0000000..ed7c56a --- /dev/null +++ b/lab12/Vasich/tree.py @@ -0,0 +1,90 @@ +class Set: + def add(self, value): + pass + + def __iter__(self): + pass + + +class UnbalancedBinarySearchTree(Set): + + class Node: + def __init__(self, value, left=None, right=None, parent=None): + self.value = value + self.left = left + self.right = right + self.parent = parent + + def set_left(self, value): + self.left = UnbalancedBinarySearchTree.Node(value, None, None, self) + + def set_right(self, value): + self.right = UnbalancedBinarySearchTree.Node(value, None, None, self) + + def __init__(self): + self.root = None + + def add(self, value): + if self.root is None: + self.root = UnbalancedBinarySearchTree.Node(value) + else: + curr = prev = self.root + while curr is not None: + prev = curr + if value <= curr.value: + curr = curr.left + else: + curr = curr.right + + if value <= prev.value: + prev.set_left(value) + else: + prev.set_right(value) + + def contains(self, value): + curr = self.root + + while curr is not None: + if value > curr.value: + curr = curr.right + elif value < curr.value: + curr = curr.left + else: + return True + + return False + + def iterate(self): + prev = None + curr = self.root + if curr is None: + yield from () + return + + up_from_right = False + + while up_from_right is False: + while curr.left is not prev and curr.left is not None: + curr = curr.left + + value = curr.value + prev = curr + + if curr.right is not None: + curr = curr.right + else: + up_from_right = True + while up_from_right is True and curr.parent is not None: + up_from_right = curr.parent.right is curr + prev = curr + curr = curr.parent + + yield value + + def __iter__(self): + # approach with yield, can be inlined into this method too, extracted for example purposes + return self.iterate() + # manual approach with next() and StopIteration(). Isn't preferred + # return TreeGeneratorManual(self) + # we can also just use the generator from list in this example + # return self.values.__iter__() From 7db8a6cdc4a21d3f6cbae567b821d60d21ee6b4a Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 07:15:08 +0300 Subject: [PATCH 13/30] lab 13 --- lab13/Vasich/splay_tree.py | 154 +++++++++++++++++++++++++++++++++++++ lab13/Vasich/tests.py | 102 ++++++++++++++++++++++++ 2 files changed, 256 insertions(+) create mode 100644 lab13/Vasich/splay_tree.py create mode 100644 lab13/Vasich/tests.py diff --git a/lab13/Vasich/splay_tree.py b/lab13/Vasich/splay_tree.py new file mode 100644 index 0000000..64e39ca --- /dev/null +++ b/lab13/Vasich/splay_tree.py @@ -0,0 +1,154 @@ +class Set: + def add(self, value): + pass + + def __iter__(self): + pass + + +class SplayTree(Set): + class Node: + def __init__(self, value, left=None, right=None, parent=None): + self.value = value + self.left = left + if left is not None: + left.parent = self + self.right = right + if right is not None: + right.parent = self + self.parent = parent + + def add_left(self, value): + self.left = SplayTree.Node(value, None, None, self) + + def set_left(self, node): + self.left = node + if node is not None: + node.parent = self + + def add_right(self, value): + self.right = SplayTree.Node(value, None, None, self) + + def set_right(self, node): + self.right = node + if node is not None: + node.parent = self + + def __init__(self): + self._root = None + + def _rotate(self, node): + parent = node.parent + g_parent = parent.parent + + if g_parent is not None: + if g_parent.left == parent: + g_parent.set_left(node) + else: + g_parent.set_right(node) + + node.parent = g_parent + + if parent.left == node: + parent.set_left(node.right) + node.set_right(parent) + else: + parent.set_right(node.left) + node.set_left(parent) + + def _splay(self, node): + parent = node.parent + + while parent is not None: + g_parent = parent.parent + if g_parent is not None: + if g_parent.left is parent == parent.left is node: + self._rotate(parent) + else: + self._rotate(node) + + self._rotate(node) + parent = node.parent + + self._root = node + return node + + def _find(self, value, sub_tree): + if sub_tree is None: + return None + elif value < sub_tree.value and sub_tree.left is not None: + return self._find(value, sub_tree.left) + elif value > sub_tree.value and sub_tree.right is not None: + return self._find(value, sub_tree.right) + else: + return sub_tree + + def find(self, value): + if self._root is None: + return None + else: + node = self._find(value, self._root) + if node.value == value: + self._splay(node) + return node + else: + return None + + def contains(self, value): + return self.find(value) is not None + + def split(self, value): + node = self._find(value, self._root) + + if node is None: + return None, None + + self._splay(node) + + if node.value <= value: + right = node.right + node.right = None + return node, right + else: + left = node.left + node.left = None + return left, node + + def merge(self, left, right): + if left is None: + return right + + while left.right is not None: + left = left.right + + self._splay(left) + left.set_right(right) + + def add(self, value): + left, right = self.split(value) + self._root = SplayTree.Node(value, left, right) + + def remove(self, value): + node = self.find(value) + + while node is not None: + if node.left is not None: + node.left.parent = None + if node.right is not None: + node.right.parent = None + self.merge(node.left, node.right) + node = self.find(value) + + def iterate(self, node): + if node.left is not None: + yield from self.iterate(node.left) + yield node.value + if node.right is not None: + yield from self.iterate(node.right) + + def __iter__(self): + self.rec_depth = 0 + if self._root is None: + return iter([]) + else: + return self.iterate(self._root) diff --git a/lab13/Vasich/tests.py b/lab13/Vasich/tests.py new file mode 100644 index 0000000..9e9ba82 --- /dev/null +++ b/lab13/Vasich/tests.py @@ -0,0 +1,102 @@ +from lab13.Vasich.splay_tree import SplayTree +from random import randint +import unittest + + +class TestQueue(unittest.TestCase): + def _check(self, input_arr): + tree = SplayTree() + + for v in input_arr: + tree.add(v) + + input_arr.sort() + i = 0 + for p in tree: + if p != input_arr[i]: + return False + i += 1 + return True + + def test_empty(self): + self.assertTrue(self._check([])) + + def test_ascending(self): + size = 500 + input_arr = [0] * size + for i in range(1, size): + input_arr[i] = input_arr[i - 1] + randint(1, 10) + self.assertTrue(self._check(input_arr)) + + def test_repeating_ascending(self): + size = 500 + input_arr = [0] * size + for i in range(1, size): + input_arr[i] = input_arr[i - 1] + randint(0, 4) + self.assertTrue(self._check(input_arr)) + + def test_descending(self): + size = 500 + input_arr = [randint(0, size)] * size + for i in range(1, size): + input_arr[i] = input_arr[i - 1] - randint(1, 10) + self.assertTrue(self._check(input_arr)) + + def test_random(self): + size = 10000 + input_arr = [0] * size + for i in range(size): + input_arr[i] = randint(-1000, 1000) + self.assertTrue(self._check(input_arr)) + + def test_contains(self): + size = 10000 + input_arr = [0] * size + for i in range(size): + input_arr[i] = randint(-1000, 1000) + + tree = SplayTree() + for v in input_arr: + tree.add(v) + + value = input_arr[randint(0, size)] + self.assertTrue(tree.contains(value)) + + def test_contains1(self): + size = 1000 + input_arr = [0] * size + for i in range(size): + input_arr[i] = randint(-1000, 1000) + + tree = SplayTree() + for v in input_arr: + tree.add(v) + + value = 1001 + self.assertFalse(tree.contains(value)) + + def test_remove_zero(self): + size = 100 + input_arr = [0] * size + for i in range(size): + input_arr[i] = randint(-10, 10) + + tree = SplayTree() + for v in input_arr: + tree.add(v) + arr = [] + for i in range(size): + if input_arr[i] != 0: + arr.append(input_arr[i]) + + arr.sort() + tree.remove(0) + + j = 0 + checked = True + for p in tree: + if p != arr[j]: + checked = False + break + j += 1 + self.assertTrue(checked) From 06486a90d3b0d3da508bbba041b3ebb6a386a6e1 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 07:18:12 +0300 Subject: [PATCH 14/30] Delete generators.cpython-35.pyc --- .../Vasich/__pycache__/generators.cpython-35.pyc | Bin 1349 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lab7/Vasich/__pycache__/generators.cpython-35.pyc diff --git a/lab7/Vasich/__pycache__/generators.cpython-35.pyc b/lab7/Vasich/__pycache__/generators.cpython-35.pyc deleted file mode 100644 index e6357e157c9fa0a4173f1a72873d14c53ba3b39c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1349 zcmbtU&1w@-6h3!mGWqGGt+h>R7ve&Y5foiWQG$p?x+{fZg)mUZ%r!}yN$kDppG-ik z58xXJ?tB1ug0IkST#QRseE`?`ojYkrLl=UVxhLP;oO|v$-*?Yc%H`7Qoz=}bhv*lL z4GZ`Qre24M@CfP<#e(XBL}XE9(+8qDfJ0HvV4EVBqP)RaEKpQ5I7d;5qA7#n;L(O( zK0{RUMVeP(H)?nL4VxD*a+r))F!d@74sHrcESewS06_zX4)0Ln@X`*EdP;qw1dpI& zixQjvs$n9>W%%w^=mi!xe0xm^ggay73&r*Mxzz6T4pOJpZnjcKx8KUt)^ax$?JuN? z@c8`SSh7ZK+v!jD+Ddcp71D0F3IzjXbsq*A!K6<2piJ zpbcNF`IZqEdE#{6xvZ4QY%8H|NbZg1g_LjNK+W}&m_veU4(NYV;~3~fxsOXO|1G;} zBri?xHbRZ3H$RykD{Pos0vIue%azeKY<0ugut_J`s@vVYc#^GI9mX<~J(KnxC&Drj zx=StKcg@eIZq|gR`;8(-T0^4ZRE^_UZ2kr)b9oB2ti>Pm_e1m2tnC%Os^@y{Up;U0 A$^ZZW From 108e59047f0756a9c54e6e5284440e7063e82139 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sun, 15 Nov 2015 07:18:41 +0300 Subject: [PATCH 15/30] Delete combine_sort.cpython-35.pyc --- .../__pycache__/combine_sort.cpython-35.pyc | Bin 1551 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lab4/Vasich/__pycache__/combine_sort.cpython-35.pyc diff --git a/lab4/Vasich/__pycache__/combine_sort.cpython-35.pyc b/lab4/Vasich/__pycache__/combine_sort.cpython-35.pyc deleted file mode 100644 index cffb0108432b7e166c0b35b0ba9311b6f823676e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1551 zcmZ8hON$#v5U%cdNTZj<#_X=v2Ky8kaEvz?9E@TDHsqAW;KTtT$BZ>?X`~rFdd5To z2|_kMAo&S7=8#)*%a2%J`Uk8q6npdwQO~CsU&YQV6jvz@ z?7T`!&^VxT?5RhLCZB2L~Fr89<3#vOM3Qd zNE?UNU^~>=xcr0kc;nHsOKXHFY2uMi?G}$ZYnLYO^))oH3kP<~{})hQoYME$$fxdP zi<{sO0&vc@0VSbf`k#IJsJIP?0W-qo%PDW8+NJ%829-(k<-%?`x2!kNe-{ zO6UEHU*G@q{^yIoFaGI2Ukyf)&YtVpSPhE2pUvWTsXFba(VK_;mrwKn*`}37)B~u(zB(teyRdICQ1|e}GYIyI61JT0J%pABZ!BfZBXEZf6 z&fAb^<6Byx&m4r zOb3^`DRix1rwfa)!!)4f4?ENWt@Ys>+SJ$wnC?Ier*tMjWV`3Vu^M$D2KbL~&f+gN z%lp`876qj!V9_P67E;Yc7do2T%J|WI4k$IJFRW`$vJR{uOX4_Hy2cBcoML=#+*G|S zP!P#*ROlw}<#Zb{vFMlN26Mbj>7n`r)BIBqvVi%*mxrPwn!-|vHD)&fVpFz6OX_3n z+_wgMvqE)o6XSl^42KS+m*F2T=YfA^H}0pJC+OCM4Pjx{dcx zwxyK~xY_t&%N)AB5pH9GT7_4y4rn8GMS{xvP13@r7uHI7u@ty)%w-@)&LxO*11(b%h8Gh6e$WZWz&Mz$jK2{XCB%6K^nQ`IVpQ*HCvej!gWV|1BQYai+Xyc@6dd(jWUfTkxcFQZ^3CC^Q`cSkT-)YnvCyho! H+!p@>mKh`t From 0643e75a358419e13f2c3e07918c9655acf5fc9e Mon Sep 17 00:00:00 2001 From: graystrappado Date: Thu, 19 Nov 2015 09:07:34 +0300 Subject: [PATCH 16/30] lab 15 --- lab15/Vasich/lca_to_rmq.py | 130 +++++++++++++++++++++++++++++++++++++ lab15/Vasich/tests.py | 63 ++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 lab15/Vasich/lca_to_rmq.py create mode 100644 lab15/Vasich/tests.py diff --git a/lab15/Vasich/lca_to_rmq.py b/lab15/Vasich/lca_to_rmq.py new file mode 100644 index 0000000..684ade7 --- /dev/null +++ b/lab15/Vasich/lca_to_rmq.py @@ -0,0 +1,130 @@ +from math import log2 +from sys import stdin + + +class LCATree: + def __init__(self, root, vertex_count): + self._root = root + self._vert = {root: []} + + segment_tree_size = 2 ** int(log2(2 * vertex_count - 1) + 2) - 1 + + self._depths = [(None, float("inf"))] * (2 * vertex_count) + self._depths_indices = {None: len(self._depths) - 1} + + self._segment_tree = [-1] * segment_tree_size + + def add_vertex(self, v): + if v not in self._vert: + self._vert[v] = [] + + def add_link(self, v1, v2): + if v1 not in self._vert: + self._vert[v1] = [] + if v2 not in self._vert: + self._vert[v2] = [] + self._vert[v1].append(v2) + self._vert[v2].append(v1) + + def prepare(self): + self._dfs(self._root, 0, 0) + self._construct_segment_tree(0, len(self._depths) - 1, 0) + + def get_mid(self, start, end): + return (start + end + 1) // 2 + + def _dfs(self, v, depth, index): + self._depths[index] = (v, depth) + self._depths_indices[v] = index + index += 1 + + for w in self._vert[v]: + self._vert[w].remove(v) + depth += 1 + index = self._dfs(w, depth, index) + depth -= 1 + self._depths[index] = (v, depth) + index += 1 + return index + + def _construct_segment_tree(self, start, end, index): + if end - start == 1: + self._segment_tree[index] = self._depths[start][0] + else: + mid = self.get_mid(start, end) + self._construct_segment_tree(start, mid, 2 * index + 1) + self._construct_segment_tree(mid, end, 2 * index + 2) + + left_vertex = self._segment_tree[2 * index + 1] + right_vertex = self._segment_tree[2 * index + 2] + + left_depth = self._depths[self._depths_indices[left_vertex]][1] + right_depth = self._depths[self._depths_indices[right_vertex]][1] + + if left_depth <= right_depth: + self._segment_tree[index] = left_vertex + else: + self._segment_tree[index] = right_vertex + + def find_lca(self, v1, v2): + + missing_v1 = v1 not in self._depths_indices.keys() + missing_v2 = v2 not in self._depths_indices.keys() + + msg = "Missing keys:" + if missing_v1: + msg += "\tv1 = " + str(v1) + if missing_v2: + msg += "\tv2 = " + str(v2) + if missing_v1 or missing_v2: + return msg + + start = self._depths_indices[v1] + end = self._depths_indices[v2] + + if start > end: + start, end = end, start + end += 1 + + return self._find_lca(start, end, 0, len(self._depths) - 1, 0) + + def _find_lca(self, start, end, seq_start, seq_end, index): + if start <= seq_start and end >= seq_end: + return self._segment_tree[index] + elif start >= seq_end or end <= seq_start: + return None + + mid = self.get_mid(seq_start, seq_end) + left_vertex = self._find_lca(start, end, seq_start, mid, 2 * index + 1) + right_vertex = self._find_lca(start, end, mid, seq_end, 2 * index + 2) + + left_depth = self._depths[self._depths_indices[left_vertex]][1] + right_depth = self._depths[self._depths_indices[right_vertex]][1] + + if left_depth <= right_depth: + return left_vertex + else: + return right_vertex + + +if __name__ == "__main__": + vertices_line = stdin.readline() + vertices_count = int(vertices_line) + root_line = stdin.readline().split("\n")[0] + + t = LCATree(root_line, vertices_count) + + i = 0 + while i < vertices_count - 1: + link_line = stdin.readline().split("\n")[0] + v1, v2 = link_line.split() + t.add_link(v1, v2) + i += 1 + + t.prepare() + print("***") + + for line in stdin: + link_line = line.split("\n")[0] + v1, v2 = link_line.split()[:2] + print(t.find_lca(v1, v2)) diff --git a/lab15/Vasich/tests.py b/lab15/Vasich/tests.py new file mode 100644 index 0000000..75f4aba --- /dev/null +++ b/lab15/Vasich/tests.py @@ -0,0 +1,63 @@ +from lab15.Vasich.lca_to_rmq import LCATree +from random import shuffle, randint +import unittest + + +class TestLCA(unittest.TestCase): + + def test_root_only(self): + t = LCATree("root", 1) + t.prepare() + self.assertEqual(t.find_lca("root", 2), "Missing keys:\tv2 = 2") + + def test_human_evolution(self): + aust_afar = "Australopithecus Afarensis" + aust_afri = "Australopithecus Africanus" + + para_aeth = "Paranthropus Aethiopicus" + para_robu = "Paranthropus Robustus" + para_bois = "Paranthropus Boisei" + + homo_rudo = "Homo Rudolfensis" + homo_habi = "Homo Habilis" + homo_erga = "Homo Ergaster" + homo_erec = "Homo Erectus" + homo_heid = "Homo Heidelbergensis" + homo_nean = "Homo Neanderthalensis" + homo_sapi = "Homo Sapiens" + + t = LCATree(aust_afar, 12) + t.add_link(aust_afar, para_aeth) + t.add_link(para_aeth, para_robu) + t.add_link(para_aeth, para_bois) + t.add_link(aust_afar, aust_afri) + t.add_link(aust_afri, homo_rudo) + t.add_link(aust_afri, homo_habi) + t.add_link(homo_habi, homo_erga) + t.add_link(homo_erga, homo_erec) + t.add_link(homo_erga, homo_heid) + t.add_link(homo_heid, homo_nean) + t.add_link(homo_heid, homo_sapi) + + t.prepare() + + self.assertEqual(t.find_lca(homo_heid, homo_rudo), aust_afri) + self.assertEqual(t.find_lca(homo_sapi, homo_erec), homo_erga) + self.assertEqual(t.find_lca(para_aeth, homo_habi), aust_afar) + self.assertEqual(t.find_lca("Gorilla beringei", homo_erec), "Missing keys:\tv1 = Gorilla beringei") + + def test_random_order(self): + t = LCATree(3, 8) + links = [(1, 7), (4, 7), (7, 3), (5, 3), (2, 5), (6, 2), (8, 2)] + shuffle(links) + + for link in links: + i = randint(0, 1) + t.add_link(link[i], link[1 - i]) + + t.prepare() + + self.assertEqual(t.find_lca(1, 8), 3) + self.assertEqual(t.find_lca(6, 2), 2) + self.assertEqual(t.find_lca(2, 6), 2) + self.assertEqual(t.find_lca(1, 4), 7) From 5baf34dbefea7384bea0c249b0b2147275d476b2 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Mon, 11 Jan 2016 13:33:24 +0300 Subject: [PATCH 17/30] lab 4 bugfix --- lab4/Vasich/combine_sort.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lab4/Vasich/combine_sort.py b/lab4/Vasich/combine_sort.py index a424542..a15a49a 100644 --- a/lab4/Vasich/combine_sort.py +++ b/lab4/Vasich/combine_sort.py @@ -42,7 +42,7 @@ def merge(seq, start, middle, end): def merge_sort(seq, start, end): if end - start > insertion_max: - middle = (start + end) // 2 + middle = start + (end - start) // 2 merge_sort(seq, start, middle) merge_sort(seq, middle, end) merge(seq, start, middle, end) From 5ce933497ca6c4cd1ae87c71cad25bf2afe76470 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Mon, 11 Jan 2016 13:49:31 +0300 Subject: [PATCH 18/30] lab 11 - repetitions removed --- lab11/Vasich/bar_chart.py | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/lab11/Vasich/bar_chart.py b/lab11/Vasich/bar_chart.py index 3561ba7..d37f6ae 100644 --- a/lab11/Vasich/bar_chart.py +++ b/lab11/Vasich/bar_chart.py @@ -1,14 +1,9 @@ - -def chart_area(seq): - if len(seq) < 3: - return 0 - +def one_pass_sum(seq, indices): max_sum = float("-inf") - - height = seq[0] curr_sum = 0 + height = seq[indices[0]] - for i in range(1, len(seq)): + for i in indices[1:]: if seq[i] < height: curr_sum += height - seq[i] else: @@ -16,18 +11,14 @@ def chart_area(seq): max_sum = curr_sum height = seq[i] curr_sum = 0 + return max_sum - height = seq[len(seq) - 1] - curr_sum = 0 - for i in range(len(seq) - 2, -1, -1): - if seq[i] < height: - curr_sum += height - seq[i] - else: - if curr_sum >= max_sum: - max_sum = curr_sum - height = seq[i] - curr_sum = 0 +def chart_area(seq): + if len(seq) < 3: + return 0 - return max_sum + forward = one_pass_sum(seq, range(len(seq))) + backward = one_pass_sum(seq, range(len(seq) - 1, -1, -1)) + return max(forward, backward) From f8016a7cb479f2c83f69073a3fc943df28553a54 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Mon, 11 Jan 2016 13:52:10 +0300 Subject: [PATCH 19/30] lab 12 - redundant line removed --- lab12/Vasich/tree.py | 1 - 1 file changed, 1 deletion(-) diff --git a/lab12/Vasich/tree.py b/lab12/Vasich/tree.py index ed7c56a..8c9d5c9 100644 --- a/lab12/Vasich/tree.py +++ b/lab12/Vasich/tree.py @@ -58,7 +58,6 @@ def iterate(self): prev = None curr = self.root if curr is None: - yield from () return up_from_right = False From 3dfd33e97973e62d4ea3c919433ca271b4ae1b1b Mon Sep 17 00:00:00 2001 From: graystrappado Date: Mon, 11 Jan 2016 14:19:20 +0300 Subject: [PATCH 20/30] lab 2 - oops! right code now --- lab2/Vasich/sieve_of_eratosthenes.py | 167 +++------------------------ 1 file changed, 13 insertions(+), 154 deletions(-) diff --git a/lab2/Vasich/sieve_of_eratosthenes.py b/lab2/Vasich/sieve_of_eratosthenes.py index 64e39ca..d65b9cf 100644 --- a/lab2/Vasich/sieve_of_eratosthenes.py +++ b/lab2/Vasich/sieve_of_eratosthenes.py @@ -1,154 +1,13 @@ -class Set: - def add(self, value): - pass - - def __iter__(self): - pass - - -class SplayTree(Set): - class Node: - def __init__(self, value, left=None, right=None, parent=None): - self.value = value - self.left = left - if left is not None: - left.parent = self - self.right = right - if right is not None: - right.parent = self - self.parent = parent - - def add_left(self, value): - self.left = SplayTree.Node(value, None, None, self) - - def set_left(self, node): - self.left = node - if node is not None: - node.parent = self - - def add_right(self, value): - self.right = SplayTree.Node(value, None, None, self) - - def set_right(self, node): - self.right = node - if node is not None: - node.parent = self - - def __init__(self): - self._root = None - - def _rotate(self, node): - parent = node.parent - g_parent = parent.parent - - if g_parent is not None: - if g_parent.left == parent: - g_parent.set_left(node) - else: - g_parent.set_right(node) - - node.parent = g_parent - - if parent.left == node: - parent.set_left(node.right) - node.set_right(parent) - else: - parent.set_right(node.left) - node.set_left(parent) - - def _splay(self, node): - parent = node.parent - - while parent is not None: - g_parent = parent.parent - if g_parent is not None: - if g_parent.left is parent == parent.left is node: - self._rotate(parent) - else: - self._rotate(node) - - self._rotate(node) - parent = node.parent - - self._root = node - return node - - def _find(self, value, sub_tree): - if sub_tree is None: - return None - elif value < sub_tree.value and sub_tree.left is not None: - return self._find(value, sub_tree.left) - elif value > sub_tree.value and sub_tree.right is not None: - return self._find(value, sub_tree.right) - else: - return sub_tree - - def find(self, value): - if self._root is None: - return None - else: - node = self._find(value, self._root) - if node.value == value: - self._splay(node) - return node - else: - return None - - def contains(self, value): - return self.find(value) is not None - - def split(self, value): - node = self._find(value, self._root) - - if node is None: - return None, None - - self._splay(node) - - if node.value <= value: - right = node.right - node.right = None - return node, right - else: - left = node.left - node.left = None - return left, node - - def merge(self, left, right): - if left is None: - return right - - while left.right is not None: - left = left.right - - self._splay(left) - left.set_right(right) - - def add(self, value): - left, right = self.split(value) - self._root = SplayTree.Node(value, left, right) - - def remove(self, value): - node = self.find(value) - - while node is not None: - if node.left is not None: - node.left.parent = None - if node.right is not None: - node.right.parent = None - self.merge(node.left, node.right) - node = self.find(value) - - def iterate(self, node): - if node.left is not None: - yield from self.iterate(node.left) - yield node.value - if node.right is not None: - yield from self.iterate(node.right) - - def __iter__(self): - self.rec_depth = 0 - if self._root is None: - return iter([]) - else: - return self.iterate(self._root) +def sieve(n): + primes = [m % 2 == 1 for m in range(n + 1)] + primes[1] = False + primes[2] = True + + for i in range(2, int(n ** 0.5) + 1): + if primes[i]: + for p in range(i ** 2, n + 1, 2 * i): + primes[p] = False + return primes + +q = int(input()) +print(sieve(q)) From 8f9ae93e51451f157cd7f3ca45c926374788e6f9 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sat, 26 Mar 2016 19:59:53 +0300 Subject: [PATCH 21/30] Update splay_tree.py --- lab13/Vasich/splay_tree.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lab13/Vasich/splay_tree.py b/lab13/Vasich/splay_tree.py index 64e39ca..7f0c1d1 100644 --- a/lab13/Vasich/splay_tree.py +++ b/lab13/Vasich/splay_tree.py @@ -7,7 +7,13 @@ def __iter__(self): class SplayTree(Set): + """ + A SplayTree implementation of Set interface. + A SplayTree maintains a set of elements drawn from a totally ordered set and allowing membership testing, + insertions, and deletions (among other operations) at an amortized cost of O(log n) per operation. + """ class Node: + """Node structure.""" def __init__(self, value, left=None, right=None, parent=None): self.value = value self.left = left @@ -38,6 +44,7 @@ def __init__(self): self._root = None def _rotate(self, node): + """Rotate node with respect to its parent""" parent = node.parent g_parent = parent.parent @@ -57,6 +64,7 @@ def _rotate(self, node): node.set_left(parent) def _splay(self, node): + """Reorganize the splay tree so that node is at the root.""" parent = node.parent while parent is not None: @@ -74,6 +82,7 @@ def _splay(self, node): return node def _find(self, value, sub_tree): + """Find node with the closest value.""" if sub_tree is None: return None elif value < sub_tree.value and sub_tree.left is not None: @@ -84,6 +93,7 @@ def _find(self, value, sub_tree): return sub_tree def find(self, value): + """Find node by the value and splay tree in it. Return None tree contains no nodes with this value.""" if self._root is None: return None else: @@ -95,9 +105,12 @@ def find(self, value): return None def contains(self, value): + """True if value presented in tree""" return self.find(value) is not None def split(self, value): + """Split tree into two subtrees. Elements of left subtree are equal or less than value, + elements of right one are """ node = self._find(value, self._root) if node is None: @@ -115,6 +128,7 @@ def split(self, value): return left, node def merge(self, left, right): + """Merge two trees into one.""" if left is None: return right @@ -125,10 +139,12 @@ def merge(self, left, right): left.set_right(right) def add(self, value): + """Split tree by the value and use it as a root for new tree.""" left, right = self.split(value) self._root = SplayTree.Node(value, left, right) def remove(self, value): + """Remove node from tree.""" node = self.find(value) while node is not None: From 7a0e6a9c2950c0fd3d6f3f365fe71ce4352f1403 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sat, 26 Mar 2016 20:02:12 +0300 Subject: [PATCH 22/30] Update tree.py --- lab12/Vasich/tree.py | 103 ++++++++++++++++--------------------------- 1 file changed, 38 insertions(+), 65 deletions(-) diff --git a/lab12/Vasich/tree.py b/lab12/Vasich/tree.py index 8c9d5c9..f519592 100644 --- a/lab12/Vasich/tree.py +++ b/lab12/Vasich/tree.py @@ -1,3 +1,4 @@ + class Set: def add(self, value): pass @@ -8,82 +9,54 @@ def __iter__(self): class UnbalancedBinarySearchTree(Set): - class Node: - def __init__(self, value, left=None, right=None, parent=None): - self.value = value - self.left = left - self.right = right - self.parent = parent - - def set_left(self, value): - self.left = UnbalancedBinarySearchTree.Node(value, None, None, self) - - def set_right(self, value): - self.right = UnbalancedBinarySearchTree.Node(value, None, None, self) - - def __init__(self): - self.root = None + def __init__(self, value=None, parent=None): + self.value = value + self.parent = parent + self.left = None + self.right = None def add(self, value): - if self.root is None: - self.root = UnbalancedBinarySearchTree.Node(value) - else: - curr = prev = self.root - while curr is not None: - prev = curr - if value <= curr.value: + if self.parent is None: + self.parent = self + self.value = value + return self + + curr = self + while True: + if value <= curr.value: + if curr.left: curr = curr.left else: - curr = curr.right - - if value <= prev.value: - prev.set_left(value) + curr.left = UnbalancedBinarySearchTree(value, curr) + break else: - prev.set_right(value) + if curr.right: + curr = curr.right + else: + curr.right = UnbalancedBinarySearchTree(value, curr) + break + return self def contains(self, value): - curr = self.root - - while curr is not None: - if value > curr.value: - curr = curr.right - elif value < curr.value: - curr = curr.left - else: + curr = self + while curr: + if value == curr.value: return True - + curr = curr.left if value <= curr.value else curr.right return False def iterate(self): - prev = None - curr = self.root - if curr is None: - return - - up_from_right = False - - while up_from_right is False: - while curr.left is not prev and curr.left is not None: - curr = curr.left - - value = curr.value - prev = curr - - if curr.right is not None: - curr = curr.right - else: - up_from_right = True - while up_from_right is True and curr.parent is not None: - up_from_right = curr.parent.right is curr - prev = curr - curr = curr.parent - - yield value + if self.left: + yield from self.left + yield self.value + if self.right: + yield from self.right def __iter__(self): - # approach with yield, can be inlined into this method too, extracted for example purposes + if self.parent is None: + return iter([]) return self.iterate() - # manual approach with next() and StopIteration(). Isn't preferred - # return TreeGeneratorManual(self) - # we can also just use the generator from list in this example - # return self.values.__iter__() + + +if __name__ == "__main__": + pass From 2b4c6ccebe98daa723eba558a5278abc0999a822 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sat, 26 Mar 2016 20:03:10 +0300 Subject: [PATCH 23/30] Added files via upload --- lab14/Vasich/tests.py | 49 +++++++++++++++++++++++++++++ lab14/Vasich/topological_sorting.py | 32 +++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 lab14/Vasich/tests.py create mode 100644 lab14/Vasich/topological_sorting.py diff --git a/lab14/Vasich/tests.py b/lab14/Vasich/tests.py new file mode 100644 index 0000000..9286886 --- /dev/null +++ b/lab14/Vasich/tests.py @@ -0,0 +1,49 @@ +from lab14.Vasich.topological_sorting import Graph +import unittest +import random + + +def _has_cycle(graph): + flag = {v: "to_traverse" for v in graph._vert} + + def dfs(v): + if flag[v] != "to_traverse": + return flag[v] != "traversed" + flag[v] = "traversing" + if any(dfs(w) for w in graph._vert[v]): + return True + flag[v] = "traversed" + return False + + return any(dfs(v) for v in graph._vert) + + +class TestTopologicalSorting(unittest.TestCase): + + def _check(self, graph): + result = graph.topological_sort() + if result: + self.assertEqual(len(result), len(graph._vert)) + self.assertFalse(any(v in graph._vert[g] + for i, v in enumerate(result) for g in result[i:])) + else: + self.assertTrue(_has_cycle(graph)) + + def test_manual(self): + g = Graph() + g.\ + add_directed_link(1, 2).add_directed_link(1, 3).\ + add_directed_link(3, 5).add_directed_link(3, 0).\ + add_directed_link(101, 0).add_directed_link(4, 10).\ + add_directed_link(3, 101) + self._check(g) # without cycles + + g.add_directed_link(1, 4).add_directed_link(10, 1) + self._check(g) # with cycle + + def test_random(self): + for i in range(100): + graph = Graph() + for (v1, v2) in ((random.randint(0, 20), random.randint(0, 20)) for _ in range(15)): + graph.add_directed_link(v1, v2) + self._check(graph) diff --git a/lab14/Vasich/topological_sorting.py b/lab14/Vasich/topological_sorting.py new file mode 100644 index 0000000..f889c4e --- /dev/null +++ b/lab14/Vasich/topological_sorting.py @@ -0,0 +1,32 @@ +from collections import defaultdict + +class Graph: + def __init__(self): + self._vert = {} + + def add_vertex(self, v): + self._vert.setdefault(v, []) + return self + + def add_directed_link(self, v1, v2): + self._vert.setdefault(v1, []).append(v2) + self._vert.setdefault(v2, []) + return self + + def topological_sort(self): + flag = {v: "white" for v in self._vert} + result = [] + + def dfs(v): + if flag[v] != "white": + return flag[v] == "black" + flag[v] = "gray" + if not all(dfs(w) for w in self._vert[v]): + return False + flag[v] = "black" + result.append(v) + return True + + return result[::-1] if all(dfs(v) for v in self._vert) else None + + From 3d33a1cbdc585640877ebe4bce545d67cf660159 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Sat, 26 Mar 2016 20:03:48 +0300 Subject: [PATCH 24/30] Added files via upload --- lab16/Vasich/dijkstra.py | 50 ++++++++ lab16/Vasich/tests | 56 +++++++++ lab17/Vasich/__pycache__/dsu.cpython-35.pyc | Bin 0 -> 2920 bytes lab17/Vasich/dsu.py | 54 +++++++++ lab17/Vasich/kruskal.py | 41 +++++++ lab17/Vasich/tests.py | 120 ++++++++++++++++++++ lab18/Vasich/damerau_levenstein.py | 42 +++++++ lab18/Vasich/tests.py | 16 +++ lab19/Vasich/palindrome.py | 40 +++++++ lab19/Vasich/tests.py | 39 +++++++ 10 files changed, 458 insertions(+) create mode 100644 lab16/Vasich/dijkstra.py create mode 100644 lab16/Vasich/tests create mode 100644 lab17/Vasich/__pycache__/dsu.cpython-35.pyc create mode 100644 lab17/Vasich/dsu.py create mode 100644 lab17/Vasich/kruskal.py create mode 100644 lab17/Vasich/tests.py create mode 100644 lab18/Vasich/damerau_levenstein.py create mode 100644 lab18/Vasich/tests.py create mode 100644 lab19/Vasich/palindrome.py create mode 100644 lab19/Vasich/tests.py diff --git a/lab16/Vasich/dijkstra.py b/lab16/Vasich/dijkstra.py new file mode 100644 index 0000000..1e7ef98 --- /dev/null +++ b/lab16/Vasich/dijkstra.py @@ -0,0 +1,50 @@ +from math import inf +import heapq + + +class WeightedGraph: + def __init__(self): + self._vert = {} + self._prev = {} + self._dist = {} + + def add_vertex(self, v): + self._vert.setdefault(v, []) + + def add_direct_link(self, v1, v2, weight): + self._vert.setdefault(v1, []).append((v2, weight)) + self._vert.setdefault(v2, []) + + def paths(self, w): + self._dijkstra(w) + res = {v: [] for v in self._vert} + for (v, path) in res.items(): + if self._dist[v] == inf: + continue + while v is not None: + path.append(v) + v = self._prev[v] + path.reverse() + return res + + def _dijkstra(self, w): + for v in self._vert: + self._prev[v] = None + self._dist[v] = inf + self._dist[w] = 0 + q = [(self._dist[v], v) for v in self._vert] + heapq.heapify(q) + + while q: + _, u = heapq.heappop(q) + for (v, weight) in self._vert[u]: + if self._dist[v] > self._dist[u] + weight: + q.remove((self._dist[v], v)) + heapq.heapify(q) + self._dist[v] = self._dist[u] + weight + self._prev[v] = u + heapq.heappush(q, (self._dist[v], v)) + + +if __name__ == "__main__": + pass \ No newline at end of file diff --git a/lab16/Vasich/tests b/lab16/Vasich/tests new file mode 100644 index 0000000..1bdf750 --- /dev/null +++ b/lab16/Vasich/tests @@ -0,0 +1,56 @@ +import operator +import unittest +import random +from itertools import groupby + +from lab16.Vasich.dijkstra import WeightedGraph + + +def _check(graph): + + def result_distances(): + return {(start, end): sum(edges[(e1, e2)] for (e1, e2) in zip(path, path[1:])) + for start in graph._vert + for (end, path) in graph.paths(start).items()} + + def shortest_edges(): + return {(start, end): min(min(paths_to_end, key=operator.itemgetter(1))) + for start, edges in graph._vert.items() + for end, paths_to_end in groupby(sorted(edges), key=operator.itemgetter(0))} + + edges = shortest_edges() + distances = result_distances() + + def dfs(v): + if traversed[v]: + return True + nonlocal path + if path < distances[(start, v)]: + return False + traversed[v] = True + for (u, w) in graph._vert[v]: + path += w + if not dfs(u): + return False + path -= w + traversed[v] = False + return True + + for start in graph._vert: + traversed = {v: False for v in graph._vert} + path = 0 + if not dfs(start): + return False + return True + + +class TestDijkstra(unittest.TestCase): + + def test_random(self): + for i in range(1000): + graph = WeightedGraph() + for (v1, v2, w) in ( + (random.randint(0, 12), random.randint(0, 12), random.randint(1, 100)) for _ in range(20)): + graph.add_direct_link(v1, v2, w) + self.assertTrue(self._check(graph)) + diff --git a/lab17/Vasich/__pycache__/dsu.cpython-35.pyc b/lab17/Vasich/__pycache__/dsu.cpython-35.pyc new file mode 100644 index 0000000000000000000000000000000000000000..edf984b35df5907c9bd6556e518979119f4811da GIT binary patch literal 2920 zcmbVOOK%%h6h3!mY$vXhv`Gu3>Lbwdm?Eqego?llm0GD{6IHUBR*|cb@k~-T6Wh6C zqr^%PBD|JG;!m()$Bs4Yb~{^E-NS|reBT*+>@-~DkhRc(%mAofmLBgW)U`i6sC|{ItR>HFK5T1~*qWp}6bGUOpE#Io&{j3v4 zdr{cpoqYIp@!rIn_#l1!j2sv_)Zc+fpo(m%@HEHJL~x+9_8jZQ_fjuzC;hZwo1LvF zEd{-%jXD?y5N!KS>LpRU3ECb;KZ~8kp1(c?x%qM9ZW7s~@$|{FubzGV^w+1qHSX-U z9yaaH9ou~rwfae8ryCC9=vpIgetzwGW4)QQTMrvyGN|_U)0rS>ciQ~``ayROM9dj8 zT$-S)j#s=K?kCs*JdZ$)EaTmF#a>krz~&P$L_VnH+;ZJFYrbO(I3)Ep+no@D5(j2a zF=nI;iLHPjdL$tcvt-Vj;lh-f+})xV`0zl2QIGrtCchGjJa)%JhYot|$pIvuY&&AB z>K3ks!Y%-1oF~iM(BVFpQRHy4*7-U;y;d{@C) z0#j4?1vP@5gCI5g8^yiAcDwzJ;=X=guuNJQblTm{2`o-dgNRwcU&VONS##2vGiS{y zGdwwEDP5kMiYDW$raA|P_|%&dpQ)W-9(9*dZJ{(Br8?RLa*WA|ztWkcxf2CR)L(`? z(NsAaSL68>ZNP_Lo=I(z8z4xd??pC|z?#F~X;%H9=4K{~eCx>aXpEZS=@@n67Bt5X zC1Nca(wrCsaDpo+ zVSPkD=3LHA*D~*@wV8i)>T(WbD>L}w#Ne>=kB;mXr9O!q1l1xIr>32nFD7EERxQ_9 zAzR&@-s%dEWk}7+@bVNy8zJ7NEShhyT#O<+8+8Udk!|*)tme3J)X}^f8}o%AF6fCD zd0kc;FCI-LonG^2Sw}mJ_aH3?K~`|VSAt-7(2TPg%M8sj{UkZYl6{qgQ8I-#4K=M7<;Tl^;LAc&qrbvR;X?+R1u)`K^gWm!zId?MqrGMqI@N6hY$-0OSX z_^5Dn(uhH_Yw;PfWMw`t++_wy}w2%yXkyS&F>eEKK)s17cK~%`p zYxkoa-=woa(2AQ$5(JZarJLR)fEf@${hTu^S-~2?J>Ce3mtmo}?}1_MfchfaC9(Ap z&rXsj4GaUoC_0LtSUtjJ#Q{o~gree<2}3*SwbV5W;$pMci#lNz$D^|R z7H3}rL14d4J`XBXlrVf3qJ&w+W^n<{bjb|oC!Vch$&m(;qkJ7(GVc-=bcHL~_cIRV z7}!)_H&aj}othu(7snK{T>C!Waq(i$8r%MO&-&jgY2N)umALl9DV6wt(O9K%|ME-r z0+v`-3A;j~iSCn|Bzj(0#<*#HOLNkt8gv!2SX?YEx+>+rMNEAiysS8+GqtSFtZIc| Ifm^!tFPty~WdHyG literal 0 HcmV?d00001 diff --git a/lab17/Vasich/dsu.py b/lab17/Vasich/dsu.py new file mode 100644 index 0000000..edbab28 --- /dev/null +++ b/lab17/Vasich/dsu.py @@ -0,0 +1,54 @@ +class DSUIndexed: + def __init__(self, size): + self._parent = list(range(size)) + self._rank = [0] * size + + def find(self, x): + if self._parent[x] != x: + self._parent[x] = self.find(self._parent[x]) + return self._parent[x] + + def union(self, x, y): + x_root = self.find(x) + y_root = self.find(y) + if x_root == y_root: + return + + if self._rank[x_root] < self._rank[y_root]: + self._parent[x_root] = y_root + else: + self._parent[y_root] = x_root + if self._rank[x_root] == self._rank[y_root]: + self._rank[x_root] += 1 + return self + + def same_set(self, x, y): + return self.find(x) == self.find(y) + + def single_set(self): + return all(DSUIndexed.same_set(self, x, y) for (x, y) in zip(self._parent[1:], self._parent[:-1])) + + def reset(self): + self._parent = [i for i, v in enumerate(self._parent)] + self._rank = [0] * len(self._rank) + + +class DSUGeneral(DSUIndexed): + def __init__(self, collection): + self._id = dict() + for item in collection: + self._id.setdefault(item, len(self._id)) + super().__init__(len(self._id)) + + def add(self, item): + if item not in self._id: + i = self._id.setdefault(item, len(self._id)) + super()._parent.append(i) + super()._rank.append(i) + return self + + def union(self, x, y): + return super().union(self._id[x], self._id[y]) + + def same_set(self, x, y): + return super().same_set(self._id[x], self._id[y]) diff --git a/lab17/Vasich/kruskal.py b/lab17/Vasich/kruskal.py new file mode 100644 index 0000000..998cee6 --- /dev/null +++ b/lab17/Vasich/kruskal.py @@ -0,0 +1,41 @@ +from lab17.Vasich.dsu import DSUGeneral +import operator + + +class WeightedGraph: + + def __init__(self): + self._vert = dict() + self._edge = dict() + self._size = 0 + + def add_vertex(self, v): + self._vert.setdefault(v, []) + return self + + def add_direct_link(self, v1, v2, weight): + self._edge[tuple(sorted((v1, v2)))] = weight + self._vert.setdefault(v1, []).append((v2, weight)) + self._vert.setdefault(v2, []).append((v1, weight)) + return self + + def remove_edge(self, v1, v2): + self._vert[v1] = [v for v in self._vert[v1] if v != v2] + self._vert[v1] = [v for v in self._vert[v2] if v != v1] + self._edge.pop(tuple(sorted((v1, v2)))) + + def mst(self): + res = WeightedGraph() + dsu = DSUGeneral(self._vert) + edges = sorted(self._edge.items(), key=operator.itemgetter(1)) + for ((v1, v2), weight) in edges: + if not dsu.same_set(v1, v2): + dsu.union(v1, v2) + res.add_direct_link(v1, v2, weight) + return res + + def weight(self): + return sum(self._edge.values()) + +if __name__ == "__main__": + pass diff --git a/lab17/Vasich/tests.py b/lab17/Vasich/tests.py new file mode 100644 index 0000000..938db89 --- /dev/null +++ b/lab17/Vasich/tests.py @@ -0,0 +1,120 @@ +import unittest +from random import sample, choice, randrange, shuffle, getrandbits +from lab17.Vasich.kruskal import WeightedGraph +from lab17.Vasich.dsu import DSUGeneral + + +class TestKruskal(unittest.TestCase): + + def check_dsu(self, dsu, sets, number_of_test): + for _ in range(number_of_test): + s = choice(sets) + item1, item2 = choice(s), choice(s) + self.assertTrue(dsu.same_set(item1, item2)) # true for items from the same category + + for _ in range(number_of_test): + s1, s2 = sample(sets, 2) + item1, item2 = choice(s1), choice(s2) + self.assertFalse(dsu.same_set(item1, item2)) # false for items from different categories + + def test_dsu(self): + + number_of_categories = 100 # initial number_of_categories + new_number_of_categories = 10 # will be merged into new_number_of_categories later + number_of_items = number_of_categories + 10 ** 5 + max_item = number_of_items + 10 ** 8 + number_of_test = 10 ** 3 + + items = sample(range(max_item), number_of_items) + sets = [[item] for item in items[:number_of_categories]] # make each category non-empty + for item in items[number_of_categories:]: # then populate + choice(sets).append(item) + + dsu = DSUGeneral(items) + + for (leader, s) in ((choice(s), s) for s in sets): # for each category pick leader + for item in s: # and merge all items in category + dsu.union(item, leader) + + self.check_dsu(dsu, sets, number_of_test) + + shuffle(sets) + sets, tail = sets[:new_number_of_categories], sets[new_number_of_categories:] + for (s, t) in ((choice(sets), t) for t in tail): + dsu.union(choice(s), choice(t)) + s.extend(t) + + self.check_dsu(dsu, sets, number_of_test) + + def check_spanning(self, tree, graph): + dsu = DSUGeneral(tree._vert) + for v in tree._vert: + for u, _ in tree._vert[v]: + dsu.union(u, v) + self.assertTrue(dsu.single_set()) + self.assertEqual(len(tree._edge), len(graph._vert) - 1) + + def test_mst_manually(self): + + graph = WeightedGraph() + graph. \ + add_direct_link(1, 2, 1).add_direct_link(1, 3, 1).add_direct_link(1, 4, 1). \ + add_direct_link(2, 3, 1).add_direct_link(2, 4, 1).add_direct_link(3, 4, 1) + mst = graph.mst() + self.check_spanning(mst, graph) + self.assertEqual(mst.weight(), 3) + + graph = WeightedGraph() + graph. \ + add_direct_link(2, 3, 1).add_direct_link(2, 4, 2).add_direct_link(3, 4, 3). \ + add_direct_link(1, 2, 3).add_direct_link(1, 3, 2).add_direct_link(1, 4, 1) + mst = graph.mst() # 1-4, 2-3, 2-4 or 1-3, 1-4, 2-3 + self.check_spanning(mst, graph) + self.assertEqual(mst.weight(), 4) + s = {(1, 4), (2, 3), (2, 4)}.symmetric_difference(set(mst._edge)) + self.assertTrue(s == {} or s == {(1, 3), (2, 4)}) + + def test_mst_random(self): + + graph = WeightedGraph() + number_of_vertices = 10 ** 3 + max_value = number_of_vertices + 10 ** 2 + number_of_chords = number_of_vertices // 2 + branching_factor = 4 + delta_weight = 30 + + vs = sample(range(max_value), number_of_vertices) + trees = [[v] for v in vs] + guaranteed = set() + possible = set() + min_weight, max_weight = 0, 0 + while len(trees) > 1: # spanning tree of the graph + min_weight, max_weight = max_weight, max_weight + delta_weight # in each iteration weight is increased + nodes_on_level = max(len(trees) // branching_factor, 1) + trees, tail = trees[:nodes_on_level], trees[nodes_on_level:] + for (tree, t) in ((choice(trees), t) for t in tail): # Cut property: + [u], [v] = sample(tree, 1), sample(t, 1) # Let S be any subset of vertices, + w = randrange(min_weight, max_weight) # and let e be the min cost edge + graph.add_direct_link(u, v, w) # with exactly one endpoint in S. + tree.extend(t) # Then the MST contains e. + e = tuple(sorted((u, v))) + if nodes_on_level > 1: # So the lightest edges must be present in the graph's MST + guaranteed.add(e) + else: # There will be more edges within the last range + possible.add(e) + i = 0 + extralarge_weight = max_weight + delta_weight + while i < number_of_chords: + (u, v) = sorted(sample(vs, 2)) + if (u, v) not in graph._edge: + if getrandbits(1): # Here they are + graph.add_direct_link(u, v, randrange(min_weight, max_weight)) # Cycle property: + possible.add((u, v)) # Let C be any cycle in G, + else: # and let f be the max cost + graph.add_direct_link(u, v, randrange(max_weight, extralarge_weight)) # edge belonging to C. + i += 1 # Then the MST + mst = graph.mst() # does not contain f. + result = set(mst._edge) + self.check_spanning(mst, graph) + self.assertTrue(guaranteed <= result) # Cut property: contains all min edges of spanning forest + self.assertTrue(result - guaranteed <= possible) # Cycle property: contains no heavy chords diff --git a/lab18/Vasich/damerau_levenstein.py b/lab18/Vasich/damerau_levenstein.py new file mode 100644 index 0000000..7342e09 --- /dev/null +++ b/lab18/Vasich/damerau_levenstein.py @@ -0,0 +1,42 @@ + +def distance(a, b): + m, n = len(a), len(b) + + if m < n: + a, b = b, a + m, n = n, m + + while n > 0 and a[m - 1] == b[n - 1]: + m -= 1 + n -= 1 + start = 0 + while start < n and a[start] == b[start]: + start += 1 + m -= start + n -= start + if n == 0: + return m + + current_row = [j for j in range(n + 1)] + old_row = [0 for _ in range(n + 1)] + + for i in range(1, m + 1): + the_oldest_row, old_row, current_row = old_row, current_row, [i] + [0] * n + for j in range(1, n + 1): + i1, j1 = start + i - 1, start + j - 1 + cost = a[i1] != b[j1] + delete, add, change = old_row[j] + 1, current_row[j - 1] + 1, old_row[j - 1] + cost + if i > 1 and j > 1 \ + and a[i1 - 1] == b[j1] \ + and a[i1] == b[j1 - 1] and cost: + swap = the_oldest_row[j - 2] + 1 + current_row[j] = min(add, delete, change, swap) + else: + current_row[j] = min(add, delete, change) + + return current_row[n] + + +#if __name__ == "__main__": +# print(distance("abc", "cb")) + diff --git a/lab18/Vasich/tests.py b/lab18/Vasich/tests.py new file mode 100644 index 0000000..7a8451e --- /dev/null +++ b/lab18/Vasich/tests.py @@ -0,0 +1,16 @@ +from lab18.Vasich.damerau_levenstein import distance +import unittest + + +class TestDLDistance(unittest.TestCase): + + def test_manual(self): + self.assertEqual(distance("хотели как лучще", "получилось как всегда"), 14) + self.assertEqual(distance("apple", "google"), 4) + + self.assertEqual(distance("Торбинс", "Сумникс"), 5) + self.assertEqual(distance("Сумникс", "Бэггинс"), 5) + self.assertEqual(distance("Бэггинс", "Беббинс"), 3) + + self.assertEqual(distance("казнить нельзя, помиловать", "казнить, нельзя помиловать"), 2) + self.assertEqual(distance("хлеб", "пиво"), 4) \ No newline at end of file diff --git a/lab19/Vasich/palindrome.py b/lab19/Vasich/palindrome.py new file mode 100644 index 0000000..72f325c --- /dev/null +++ b/lab19/Vasich/palindrome.py @@ -0,0 +1,40 @@ +import time + + +def palindrome(s): + length = len(s) + + matrix = [[i == j for i in range(length)] for j in range(length)] + + for diagonal in range(1, length): + for i, j in zip(range(length - 1), range(diagonal, length)): + if s[i] == s[j]: + matrix[i][j] = matrix[i + 1][j - 1] + 2 + else: + matrix[i][j] = max(matrix[i][j - 1], matrix[i + 1][j]) + + str_left, pal_left = 0, 0 + str_right, pal_right = length - 1, matrix[0][-1] - 1 + p = [""] * matrix[0][-1] + + while str_left <= str_right: + if str_left == str_right: + p[pal_left] = s[str_left] + break + if s[str_left] == s[str_right]: + p[pal_left] = s[str_left] + p[pal_right] = s[str_right] + str_left += 1 + str_right -= 1 + pal_left += 1 + pal_right -= 1 + else: + move = matrix[str_left + 1][str_right] > matrix[str_left][str_right - 1] + str_left += move + str_right += move - 1 + + return "".join(p) + + +if __name__ == "__main__": + pass diff --git a/lab19/Vasich/tests.py b/lab19/Vasich/tests.py new file mode 100644 index 0000000..675a6a6 --- /dev/null +++ b/lab19/Vasich/tests.py @@ -0,0 +1,39 @@ +from lab19.Vasich.palindrome import palindrome +import unittest +from random import choice, sample, randrange, shuffle, randint, getrandbits +from itertools import chain +import string + + +class TestPalindrome(unittest.TestCase): + + def test_random(self): + base_chars = list(chain(string.ascii_letters, string.digits, string.punctuation)) + + max_half_length = 3 * 10 ** 1 + number_of_tests = 10 ** 3 + + for _ in range(number_of_tests): + pal = [] + s = [] + half_length = randint(1, max_half_length) + middle = half_length + shuffle(base_chars) + pal_alph, mix_alph = base_chars[:half_length], base_chars[half_length:] + + for _ in range(half_length): + pal.append(choice(pal_alph)) + pal.extend(pal[:: -1]) + s.extend(pal) + center = "" + + for ch in sample(mix_alph, randrange(len(mix_alph))): + idx = randrange(len(s)) + if idx == middle: + center = ch + s.insert(idx, ch) + middle += idx < middle + pal.insert(half_length, center) + pal = "".join(pal) + s = "".join(s) + self.assertEqual(pal, palindrome(s)) From 721f0fa373d8b1e9f3487b1850510e2d3572f954 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Mon, 28 Mar 2016 01:38:57 +0300 Subject: [PATCH 25/30] little fix --- lab19/Vasich/palindrome.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lab19/Vasich/palindrome.py b/lab19/Vasich/palindrome.py index 72f325c..508fc53 100644 --- a/lab19/Vasich/palindrome.py +++ b/lab19/Vasich/palindrome.py @@ -1,8 +1,8 @@ -import time - def palindrome(s): length = len(s) + if length == 0: + return "" matrix = [[i == j for i in range(length)] for j in range(length)] @@ -37,4 +37,8 @@ def palindrome(s): if __name__ == "__main__": - pass + print("type \"/q\" to quit") + line = "" + while line != "/q": + print(palindrome(line)) + line = input("line = ") From 234309f85c51989ea9f036aa0f22898266f7965d Mon Sep 17 00:00:00 2001 From: graystrappado Date: Mon, 28 Mar 2016 01:54:46 +0300 Subject: [PATCH 26/30] +console input --- lab18/Vasich/damerau_levenstein.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lab18/Vasich/damerau_levenstein.py b/lab18/Vasich/damerau_levenstein.py index 7342e09..963c356 100644 --- a/lab18/Vasich/damerau_levenstein.py +++ b/lab18/Vasich/damerau_levenstein.py @@ -37,6 +37,13 @@ def distance(a, b): return current_row[n] -#if __name__ == "__main__": -# print(distance("abc", "cb")) +if __name__ == "__main__": + print("type \"/q\" to quit") + line1 = input("line 1 = ") + line2 = input("line 2 = ") + while line2 != "/q": + print("DLDistance = " + str(distance(line1, line2))) + line1 = input("line 1 = ") + line2 = input("line 2 = ") if line1 != "/q" else "/q" + From 720c4ea281ec84f7b97c701e4fad1c0ffd7219e2 Mon Sep 17 00:00:00 2001 From: graystrappado Date: Mon, 28 Mar 2016 13:08:37 +0300 Subject: [PATCH 27/30] 19 fixed --- lab19/Vasich/palindrome.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lab19/Vasich/palindrome.py b/lab19/Vasich/palindrome.py index 508fc53..a836d83 100644 --- a/lab19/Vasich/palindrome.py +++ b/lab19/Vasich/palindrome.py @@ -17,13 +17,10 @@ def palindrome(s): str_right, pal_right = length - 1, matrix[0][-1] - 1 p = [""] * matrix[0][-1] - while str_left <= str_right: - if str_left == str_right: - p[pal_left] = s[str_left] - break - if s[str_left] == s[str_right]: - p[pal_left] = s[str_left] - p[pal_right] = s[str_right] + while str_left < str_right: + symbol = s[str_left] + if symbol == s[str_right]: + p[pal_left] = p[pal_right] = symbol str_left += 1 str_right -= 1 pal_left += 1 @@ -32,13 +29,15 @@ def palindrome(s): move = matrix[str_left + 1][str_right] > matrix[str_left][str_right - 1] str_left += move str_right += move - 1 + if str_left == str_right: + p[pal_left] = s[str_left] return "".join(p) if __name__ == "__main__": print("type \"/q\" to quit") - line = "" + line = input("line = ") while line != "/q": print(palindrome(line)) line = input("line = ") From aa28582b5e4dc54df31f60e29739f5e6d8794d3c Mon Sep 17 00:00:00 2001 From: graystrappado Date: Mon, 28 Mar 2016 13:11:23 +0300 Subject: [PATCH 28/30] 19 test rewritten --- lab19/Vasich/tests.py | 48 ++++++++++++++++--------------------------- 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/lab19/Vasich/tests.py b/lab19/Vasich/tests.py index 675a6a6..4ec82ab 100644 --- a/lab19/Vasich/tests.py +++ b/lab19/Vasich/tests.py @@ -1,39 +1,27 @@ from lab19.Vasich.palindrome import palindrome import unittest -from random import choice, sample, randrange, shuffle, randint, getrandbits -from itertools import chain +from itertools import accumulate +from random import choice import string +import operator class TestPalindrome(unittest.TestCase): - def test_random(self): - base_chars = list(chain(string.ascii_letters, string.digits, string.punctuation)) - - max_half_length = 3 * 10 ** 1 + def test_better(self): number_of_tests = 10 ** 3 + printables = list(string.printable) - for _ in range(number_of_tests): - pal = [] - s = [] - half_length = randint(1, max_half_length) - middle = half_length - shuffle(base_chars) - pal_alph, mix_alph = base_chars[:half_length], base_chars[half_length:] - - for _ in range(half_length): - pal.append(choice(pal_alph)) - pal.extend(pal[:: -1]) - s.extend(pal) - center = "" - - for ch in sample(mix_alph, randrange(len(mix_alph))): - idx = randrange(len(s)) - if idx == middle: - center = ch - s.insert(idx, ch) - middle += idx < middle - pal.insert(half_length, center) - pal = "".join(pal) - s = "".join(s) - self.assertEqual(pal, palindrome(s)) + for length in accumulate(range(1, 7), operator.mul): # PAL: [p] + P_MIDDLE + [p] + for _ in range(number_of_tests): # LINE: LEFT + [p] + MIDDLE + [p] + RIGHT + line = [choice(printables) for _ in range(length)] # if LEFT and RIGHT intersect at y + pal = palindrome("".join(line)) # there is a bigger palindrome [y] + PAL + [y] + len_p = len(pal) + if len_p == 1: + self.assertTrue(len(set(line)) == len(line) and pal[0] == line[0]) + continue + for p in pal[0: len_p // 2 + len_p % 2]: + idx_left, idx_right = line.index(p), len(line) - line[::-1].index(p) - 1 + left, line, right = line[: idx_left], line[idx_left + 1: idx_right], line[idx_right + 1:] + self.assertTrue(set(left).isdisjoint(set(right))) + print("length {} passed".format(length)) From d28c30fb8e72dd1620e84863bbe3aee13eb9265d Mon Sep 17 00:00:00 2001 From: graystrappado Date: Mon, 28 Mar 2016 13:40:52 +0300 Subject: [PATCH 29/30] Update tests.py --- lab17/Vasich/tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lab17/Vasich/tests.py b/lab17/Vasich/tests.py index 938db89..278c91b 100644 --- a/lab17/Vasich/tests.py +++ b/lab17/Vasich/tests.py @@ -71,8 +71,8 @@ def test_mst_manually(self): mst = graph.mst() # 1-4, 2-3, 2-4 or 1-3, 1-4, 2-3 self.check_spanning(mst, graph) self.assertEqual(mst.weight(), 4) - s = {(1, 4), (2, 3), (2, 4)}.symmetric_difference(set(mst._edge)) - self.assertTrue(s == {} or s == {(1, 3), (2, 4)}) + self.assertTrue(set(mst._edge.items()) == {((1, 4), 1), ((2, 3), 1), ((2, 4), 2)} or + set(mst._edge.items()) == {((1, 3), 2), ((1, 4), 1), ((2, 3), 1)}) def test_mst_random(self): From e0a859ad79d56fb90bf6d291df45ade125bfd8ee Mon Sep 17 00:00:00 2001 From: graystrappado Date: Fri, 22 Apr 2016 03:23:23 +0300 Subject: [PATCH 30/30] faster version of the sieve --- lab2/Vasich/sieve_of_eratosthenes.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lab2/Vasich/sieve_of_eratosthenes.py b/lab2/Vasich/sieve_of_eratosthenes.py index d65b9cf..4c7f4dc 100644 --- a/lab2/Vasich/sieve_of_eratosthenes.py +++ b/lab2/Vasich/sieve_of_eratosthenes.py @@ -1,3 +1,26 @@ +from math import sqrt, floor +from itertools import chain + +#faster version +def sieve_sets(n): + if n > 3: + yield from (2, 3) + elif n == 3: + yield 2 + else: + return + + primes = set(chain(range(5, n, 6), range(7, n, 6))) + stop, v = floor(sqrt(n)), 5 + while v <= stop: + yield v + primes.remove(v) + for p in range(v * v, n, 2 * v): + primes.discard(p) + v = min(primes) + yield from sorted(primes) + + def sieve(n): primes = [m % 2 == 1 for m in range(n + 1)] primes[1] = False