def fastest_way_(a, t, e, x, n): f = Array([Array.indexed(1, 2), Array.indexed(1, 2)]) l = Array([Array.indexed(1, n), Array.indexed(1, n)]) f[1, 2] = e[1] + a[1, 1] f[2, 2] = e[2] + a[2, 1] for j in between(2, n): f[1, 1] = f[1, 2] f[2, 1] = f[2, 2] if f[1, 1] + a[1, j] <= f[2, 1] + t[2, j - 1] + a[1, j]: f[1, 2] = f[1, 1] + a[1, j] l[1, j] = 1 else: f[1, 2] = f[2, 1] + t[2, j - 1] + a[1, j] l[1, j] = 2 if f[2, 1] + a[2, j] <= f[1, 1] + t[1, j - 1] + a[2, j]: f[2, 2] = f[2, 1] + a[2, j] l[2, j] = 2 else: f[2, 2] = f[1, 1] + t[1, j - 1] + a[2, j] l[2, j] = 1 if f[1, 2] + x[1] <= f[2, 2] + x[2]: f_star = f[1, 2] + x[1] l_star = 1 else: f_star = f[2, 2] + x[2] l_star = 2 return f_star, l, l_star
def merge_(A, p, q, r): n1 = q - p + 1 n2 = r - q L = Array.indexed(1, n1) R = Array.indexed(1, n2) for i in between(1, n1): L[i] = A[p + i - 1] for j in between(1, n2): R[j] = A[q + j] i = j = 1 k = p while i <= n1 and j <= n2: if L[i] <= R[j]: A[k] = L[i] i = i + 1 else: A[k] = R[j] j = j + 1 k = k + 1 while i <= n1: A[k] = L[i] i = i + 1 k = k + 1 while j <= n2: A[k] = R[j] j = j + 1 k = k + 1
def get_random_multiple_array_list(min_size=1, max_size=10, max_value=999): list_size = random.randint(min_size, max_size) array_size = random.randint(list_size, max_size) key, next, prev = Array.indexed(1, array_size), Array.indexed(1, array_size), Array.indexed(1, array_size) list_indexes = random.sample(range(1, array_size + 1), list_size) head = None prev_index = None for index in list_indexes: key[index] = random.randint(0, max_value) if prev_index is None: head = index else: next[prev_index] = index prev[index] = prev_index prev_index = index free_indexes = [i for i in range(1, array_size + 1) if i not in list_indexes] random.shuffle(free_indexes) free = None prev_free_index = None for free_index in free_indexes: if prev_free_index is None: free = free_index else: next[prev_free_index] = free_index prev_free_index = free_index return MultipleArrayList(key, next, prev, head, free)
def setup_activities(n): start_times = Array.indexed(0, n + 1) finish_times = Array.indexed(0, n + 1) for i in between(1, n): start_times[i] = random.randint(0, 49) finish_times[i] = start_times[i] + random.randint(1, 50) start_times[0], finish_times[0] = 0, 0 start_times[n + 1], finish_times[n + 1] = math.inf, math.inf return start_times, finish_times
def make_change(n, d): c = Array.indexed(0, n) denom = Array.indexed(1, n) c[0] = 0 for j in between(1, n): c[j] = math.inf for i in between(1, d.length): if j >= d[i] and 1 + c[j - d[i]] < c[j]: c[j] = 1 + c[j - d[i]] denom[j] = d[i] return c, denom
def get_random_huge_array(max_value=999): table_size = max_value table_capacity = random.randint(1, min(20, max_value)) nelements = random.randint(0, table_capacity) table = Array.indexed(0, table_size - 1) stack = Array.indexed(1, table_capacity) keys = random.sample(range(max_value), nelements) for i, key in enumerate(keys): table[key] = i + 1 stack[i + 1] = Element(key) stack.top = len(keys) return table, stack, keys
def dynamic_activity_selector(s, f): n = s.length - 2 c = Array([Array.indexed(0, n + 1) for _ in between(0, n + 1)]) A = Array([Array.indexed(0, n + 1) for _ in between(0, n + 1)]) for l in between(2, n + 2): for i in between(0, n - l + 2): j = i + l - 1 c[i, j] = 0 A[i, j] = set() for k in between(i + 1, j - 1): q = c[i, k] + c[k, j] + 1 if f[i] <= s[k] < f[k] <= s[j] and q > c[i, j]: c[i, j] = q A[i, j] = A[i, k] | {'a' + str(k)} | A[k, j] return A[0, n + 1]
def monge_minimums(A): m = A.rows minimums_indices = _monge_minimums_indices(A) minimums = Array.indexed(1, m) for i in between(1, m): minimums[i] = A[i, minimums_indices[i]] return minimums
def permute_by_sorting(A): n = A.length P = Array.indexed(1, n) for i in between(1, n): P[i] = random(1, n ** 3) _sort_using_priorities(A, P) return A
def get_random_single_array_list(min_size=1, max_size=10, max_value=999): list_size = random.randint(min_size, max_size) array_size = 3 * random.randint(list_size, max_size) A = Array.indexed(1, array_size) list_indexes = random.sample(range(1, array_size + 1, 3), list_size) head = None prev_index = None for index in list_indexes: A[index] = random.randint(0, max_value) if prev_index is None: head = index else: A[prev_index + 1] = index A[index + 2] = prev_index prev_index = index free_indexes = [i for i in range(1, array_size + 1, 3) if i not in list_indexes] random.shuffle(free_indexes) free = None prev_free_index = None for free_index in free_indexes: if prev_free_index is None: free = free_index else: A[prev_free_index + 1] = free_index prev_free_index = free_index return SingleArrayList(A, head, free)
def greedy_make_change(n): C = Array.indexed(1, 6) d = Array([1, 2, 5, 10, 20, 50]) for i in rbetween(d.length, 1): C[i] = math.floor(n / d[i]) n %= d[i] return C
def matrix_chain_order(p): n = p.length - 1 m = Array([Array.indexed(1, n) for _ in between(1, n)]) s = Array([Array.indexed(1, n) for _ in between(1, n)]) for i in between(1, n): m[i, i] = 0 for l in between(2, n): for i in between(1, n - l + 1): j = i + l - 1 m[i, j] = math.inf for k in between(i, j - 1): q = m[i, k] + m[k + 1, j] + p[i - 1] * p[k] * p[j] if q < m[i, j]: m[i, j] = q s[i, j] = k return m, s
def _construct_secondary_hash_table_no_collisions(keys, size, h_): S = Array.indexed(0, size - 1) for k in keys: if S[h_(k)] is not None: return None S[h_(k)] = k return S
def memoized_matrix_chain(p): n = p.length - 1 m = Array([Array.indexed(1, n) for _ in between(1, n)]) for i in between(1, n): for j in between(i, n): m[i, j] = math.inf return lookup_chain(p, m, 1, n)
def assert_valid_operations(operations, word1, word2): i = 1 j = 1 m = word1.length n = word2.length result = Array.indexed(1, n) for op in operations: if op == 'copy': result[j] = word1[i] i += 1 j += 1 elif op[:11] == 'replace by ': ch = op[11:] result[j] = ch i += 1 j += 1 elif op == 'delete': i += 1 elif op[:7] == 'insert ': ch = op[7:] result[j] = ch j += 1 elif op == 'twiddle': result[j] = word1[i + 1] result[j + 1] = word1[i] i += 2 j += 2 else: assert_that(op, is_(equal_to('kill'))) assert_that(op, is_(equal_to(operations[-1]))) i = m + 1 assert_that(i, is_(equal_to(m + 1))) assert_that(result, is_(equal_to(word2)))
def get_random_direct_address_table(): table_size = random.randint(1, 10) nelements = random.randint(0, table_size) elements = [Element(key) for key in random.sample(range(table_size), nelements)] table = Array.indexed(0, table_size - 1) for element in elements: table[element.key] = element return table, elements
def memoized_lcs_length(X, Y): m = X.length n = Y.length c = Array([Array.indexed(0, n) for _ in between(0, m)], start=0) for i in between(0, m): for j in between(0, n): c[i, j] = math.inf return lookup_lcs(c, X, Y, m, n)
def lis_length(X): n = X.length c = Array.indexed(1, n) b = Array.indexed(1, n) m = 0 b_star = 0 for i in between(1, n): c[i] = 1 b[i] = 0 for j in between(1, i - 1): if X[j] <= X[i] and c[j] + 1 > c[i]: c[i] = c[j] + 1 b[i] = j if c[i] > m: m = c[i] b_star = i return m, b, b_star
def optimal_bst(p, q, n): e = Array([Array.indexed(0, n) for _ in between(1, n + 1)]) w = Array([Array.indexed(0, n) for _ in between(1, n + 1)]) root = Array([Array.indexed(1, n) for _ in between(1, n)]) for i in between(1, n + 1): e[i, i - 1] = q[i - 1] w[i, i - 1] = q[i - 1] for l in between(1, n): for i in between(1, n - l + 1): j = i + l - 1 e[i, j] = math.inf w[i, j] = w[i, j - 1] + p[j] + q[j] for r in between(i, j): t = e[i, r - 1] + e[r + 1, j] + w[i, j] if t < e[i, j]: e[i, j] = t root[i, j] = r return e, root
def test_counting_sort(self): k = 20 array, elements = get_random_array(max_value=k) actual_sorted_array = Array.indexed(1, array.length) counting_sort(array, actual_sorted_array, k) expected_array = Array(sorted(elements)) assert_that(actual_sorted_array, is_(equal_to(expected_array)))
def lcs_length_(X, Y): m = X.length n = Y.length if m < n: return lcs_length_(Y, X) c = Array([Array.indexed(0, n), Array.indexed(0, n)], start=0) for j in between(0, n): c[0, j] = 0 c[1, 0] = 0 for i in between(1, m): for j in between(1, n): if X[i] == Y[j]: c[1, j] = c[0, j - 1] + 1 else: c[1, j] = max(c[1, j - 1], c[0, j]) for j in between(1, n): c[0, j] = c[1, j] return c[1, n]
def test_recursive_matrix_chain(self): n = random.randint(1, 10) dimensions = Array([random.randint(1, 999) for _ in range(n + 1)], start=0) m = Array([Array.indexed(1, n) for _ in between(1, n)]) actual_minimum_cost = recursive_matrix_chain(dimensions, m, 1, n) expected_minimum_cost = get_minimum_matrix_product_cost(dimensions, 1, n) assert_that(actual_minimum_cost, is_(equal_to(expected_minimum_cost)))
def jobs_scheduling(t, p, d): n = p.length a = Array(list(between(1, n))) _sort_jobs_by_deadlines(a, t, p, d) for i in between(1, n): d[i] = min(d[i], n ** 2) P = Array.indexed(0, d[n]) s = Array([Array.indexed(0, d[n]) for _ in between(1, n)]) for j in between(0, d[n]): P[j] = 0 for i in between(1, n): for j in between(0, d[n]): s[i, j] = 0 for i in between(1, n): for j in rbetween(d[n], t[i]): if P[min(j, d[i]) - t[i]] + p[i] > P[j]: P[j] = P[min(j, d[i]) - t[i]] + p[i] s[i, j] = 1 return P, s, a
def binary_add(A, B): n = A.length C = Array.indexed(1, n + 1) for i in between(1, n + 1): C[i] = 0 for i in between(1, n): sum = A[i] + B[i] + C[i] C[i] = sum % 2 C[i + 1] = math.floor(sum / 2) return C
def random_hash_table(h, table_size, max_value): table = Array.indexed(0, table_size - 1) nelements = random.randint(0, table.length) keys = [random.randint(0, max_value) for _ in range(nelements)] for key in keys: i = 0 while table[h(key, i, table_size)] is not None: i += 1 table[h(key, i, table_size)] = key return table, keys
def bitonic_tsp(p): n = p.length _sort_by_x_coordinates(p) b = Array([Array.indexed(1, n) for _ in between(1, n)]) r = Array([Array.indexed(1, n) for _ in between(1, n)]) b[1, 1] = 0 for j in between(2, n): for i in between(1, j): if i == 1 or i < j - 1: b[i, j] = b[i, j - 1] + _distance(p[j - 1], p[j]) r[i, j] = j - 1 else: b[i, j] = math.inf for k in between(1, i - 1): q = b[k, i] + _distance(p[k], p[j]) if q < b[i, j]: b[i, j] = q r[i, j] = k return b, r
def _sort_by_length(A, n): numbers_by_length = Array.indexed(1, n) for number in A: if numbers_by_length[len(str(number))] is None: numbers_by_length[len(str(number))] = [] numbers_by_length[len(str(number))].append(number) for i in between(1, n): if numbers_by_length[i] is not None: numbers_by_length[i] = Array(numbers_by_length[i]) return numbers_by_length
def counting_sort(A, B, k): C = Array.indexed(0, k) for i in between(0, k): C[i] = 0 for j in between(1, A.length): C[A[j]] = C[A[j]] + 1 for i in between(1, k): C[i] = C[i] + C[i - 1] for j in rbetween(A.length, 1): B[C[A[j]]] = A[j] C[A[j]] = C[A[j]] - 1
def stack_dequeue(S): if stack_empty(S): raise RuntimeError('underflow') S_ = Array.indexed(1, S.length) S_.top = 0 while not stack_empty(S): push(S_, pop(S)) x = pop(S_) while not stack_empty(S_): push(S, pop(S_)) return x
def test_print_stations(self): n = random.randint(1, 10) l = Array([Array.indexed(1, n), Array.indexed(1, n)]) l[1, 1], l[2, 1] = 0, 0 for i in between(2, n): l[1, i], l[2, i] = random.choice([(1, 1), (1, 2), (2, 2)]) l_star = random.randint(1, 2) captured_output = io.StringIO() with redirect_stdout(captured_output): print_stations(l, l_star, n) actual_output = captured_output.getvalue().splitlines() expected_output = [] i = l_star expected_output.append('line ' + str(i) + ', station ' + str(n)) for j in rbetween(n, 2): i = l[i, j] expected_output.append('line ' + str(i) + ', station ' + str(j - 1)) assert_that(actual_output, is_(equal_to(expected_output)))
def _sort_by_character(A, p, r, position): k = ord('z') - ord('a') C = Array([0] * (k + 1), start=0) for j in between(p, r): x = ord(A[j][position - 1]) - ord('a') C[x] += 1 for i in between(1, k): C[i] += C[i - 1] B = Array.indexed(1, r - p + 1) for j in rbetween(r, p): x = ord(A[j][position - 1]) - ord('a') B[C[x]] = A[j] C[x] -= 1 A.elements[p - 1:r] = B.elements
def edit_distance(x, y, cost): m = x.length n = y.length c = Array([Array.indexed(0, n) for _ in between(0, m)]) op = Array([Array.indexed(0, n) for _ in between(0, m)]) l = Array([Array.indexed(0, n) for _ in between(0, m)]) r = Array([Array.indexed(0, n) for _ in between(0, m)]) for i in between(0, m): c[i, 0] = i * cost['delete'] (op[i, 0], l[i, 0], r[i, 0]) = ('delete', i - 1, 0) for j in between(1, n): c[0, j] = j * cost['insert'] (op[0, j], l[0, j], r[0, j]) = ('insert ' + y[j], 0, j - 1) for i in between(1, m): for j in between(1, n): c[i, j] = math.inf if x[i] == y[j]: c[i, j] = c[i - 1, j - 1] + cost['copy'] (op[i, j], l[i, j], r[i, j]) = ('copy', i - 1, j - 1) if x[i] != y[j] and c[i - 1, j - 1] + cost['replace'] < c[i, j]: c[i, j] = c[i - 1, j - 1] + cost['replace'] (op[i, j], l[i, j], r[i, j]) = ('replace by ' + y[j], i - 1, j - 1) if c[i - 1, j] + cost['delete'] < c[i, j]: c[i, j] = c[i - 1, j] + cost['delete'] (op[i, j], l[i, j], r[i, j]) = ('delete', i - 1, j) if c[i, j - 1] + cost['insert'] < c[i, j]: c[i, j] = c[i, j - 1] + cost['insert'] (op[i, j], l[i, j], r[i, j]) = ('insert ' + y[j], i, j - 1) if i >= 2 and j >= 2 and x[i] == y[j - 1] and x[i - 1] == y[j] \ and c[i - 2, j - 2] + cost['twiddle'] < c[i, j]: c[i, j] = c[i - 2, j - 2] + cost['twiddle'] (op[i, j], l[i, j], r[i, j]) = ('twiddle', i - 2, j - 2) for k in between(0, m - 1): if c[k, n] + cost['kill'] < c[m, n]: c[m, n] = c[k, n] + cost['kill'] (op[m, n], l[m, n], r[m, n]) = ('kill', k, n) return c, op, l, r
def break_lines(l, M): n = l.length L = Array.indexed(0, n) L[0] = 0 for i in between(1, n): L[i] = L[i - 1] + l[i] c = Array.indexed(0, n) p = Array.indexed(1, n) c[0] = 0 for j in between(1, n): c[j] = math.inf j0 = max(1, j - math.ceil(M / 2) + 1) for i in between(j0, j): extras = M - j + i - (L[j] - L[i - 1]) if extras < 0: lc = math.inf elif j == n: lc = 0 else: lc = extras**3 if c[i - 1] + lc < c[j]: c[j] = c[i - 1] + lc p[j] = i return c, p
def get_random_chained_direct_address_table(): table_size = random.randint(1, 10) nelements = random.randint(0, table_size) elements = [ ChainedElement(random.randint(0, table_size - 1)) for _ in range(nelements) ] table = Array.indexed(0, table_size - 1) for element in elements: list_ = table[element.key] if list_: list_.prev = element element.next = list_ table[element.key] = element return table, elements
def get_random_chained_hash_table(max_value=999): table_size = random.randint(1, 10) nelements = random.randint(0, 3 * table_size) elements = [ ChainedElement(random.randint(0, max_value)) for _ in range(nelements) ] table = Array.indexed(0, table_size - 1) h = modular_hash for element in elements: list_ = table[h(element.key, table_size)] if list_: list_.prev = element element.next = list_ table[h(element.key, table_size)] = element return table, elements, h
def counting_sort_in_place(A, k): C = Array.indexed(0, k) for i in between(0, k): C[i] = 0 for j in between(1, A.length): C[A[j]] = C[A[j]] + 1 for i in between(1, k): C[i] = C[i] + C[i - 1] C_ = Array(C.elements, start=0) i = 1 while i <= A.length - 1: key = A[i] if C_[key - 1] < i <= C_[key]: i = i + 1 else: A[i], A[C[key]] = A[C[key]], A[i] C[key] = C[key] - 1
def intersecting_chords(C): n = C.length // 2 P = Array.indexed(1, n) for k in between(1, n): P[k] = 0 intersections = 0 T = RedBlackTree(sentinel=OSNode(None)) for k in between(1, 2 * n): j = C[k] if P[j] == 0: P[j] = k os_insert(T, OSNode(k)) else: x = os_search(T, P[j]) intersections = intersections + T.root.size - os_rank(T, x) os_delete(T, x) return intersections
def tasks_scheduling_(d, w): n = d.length tasks = list(zip(['a' + str(i) for i in between(1, n)], d, w)) tasks.sort(key=lambda t: t[2], reverse=True) schedule = Array.indexed(1, n) for task in tasks: i = task[1] while i >= 1 and schedule[i] is not None: i -= 1 if i >= 1: schedule[i] = task[0] else: j = n while schedule[j] is not None: j -= 1 schedule[j] = task[0] return schedule
def counting_in_range(A, k, a, b): C = Array.indexed(0, k) for i in between(0, k): C[i] = 0 for j in between(1, A.length): C[A[j]] = C[A[j]] + 1 for i in between(1, k): C[i] = C[i] + C[i - 1] if 0 < a <= b <= k: return C[b] - C[a - 1] if 0 < a <= k < b: return C[k] - C[a - 1] if a <= 0 <= b <= k: return C[b] if a <= 0 <= k < b: return C[k] if a > k or b < 0: return 0
def lcs_length__(X, Y): m = X.length n = Y.length if m < n: return lcs_length__(Y, X) C = Array.indexed(0, n) for j in between(0, n): C[j] = 0 for i in between(1, m): p = C[0] for j in between(1, n): r = C[j] if X[i] == Y[j]: C[j] = p + 1 else: C[j] = max(C[j], C[j - 1]) p = r return C[n]
def _monge_minimums_indices(A): m = A.rows n = A.columns if m == 0: return Array([]) A_ = Matrix([A[2 * j] for j in between(1, m // 2)]) minimums_indices_even_rows = _monge_minimums_indices(A_) minimums_indices = Array.indexed(1, m) for j in between(1, m // 2): minimums_indices[2 * j] = minimums_indices_even_rows[j] for j in between(1, math.ceil(m / 2)): i = 2 * j - 1 prev_minimum_index = minimums_indices[i - 1] if i > 1 else 1 next_minimum_index = minimums_indices[i + 1] if i < m else n minimum = min([A[i, k] for k in between(prev_minimum_index, next_minimum_index)]) for k in between(prev_minimum_index, next_minimum_index): if A[i, k] == minimum: minimums_indices[i] = k break return minimums_indices
def dynamic_binary_delete(A, x): i = 0 while A[i].length == 0: i = i + 1 y = A[i][2**i - 1] j = -1 l = None while l is None: j = j + 1 l = iterative_binary_search(A[j], x) A[j][l] = y while l > 1 and A[j][l] < A[j][l - 1]: A[j][l], A[j][l - 1] = A[j][l - 1], A[j][l] while l < A[j].length and A[j][l] > A[j][l + 1]: A[j][l], A[j][l + 1] = A[j][l + 1], A[j][l] for r in between(0, i - 1): A[r] = Array.indexed(1, 2**r) for t in between(1, 2**r): A[r][t] = A[i][2**r - 2 + t] A[i] = Array([])
def activity_scheduler(s, f): n = s.length A = Array.indexed(1, n) F = Array(list(rbetween(n, 1))) F.top = n B = RedBlackTree() # events contains triples (a, b, c) where a = 0 if the event is finish of an activity and 1 if it is start, # b as the activity number, and c as the start time or the finish time events = [(0, i + 1, finish_time) for i, finish_time in enumerate(f)] + \ [(1, i + 1, start_time) for i, start_time in enumerate(s)] events.sort(key=lambda e: (e[2], e[0])) for e in events: if e[0] == 1: hall_number = pop(F) A[e[1]] = hall_number rb_insert(B, Node(e[1], data=hall_number), sentinel=B.nil) else: hall = rb_search(B.root, e[1], sentinel=B.nil) push(F, hall.data) rb_delete(B, hall, sentinel=B.nil) return A
def merge_sorted_lists(lists): k = lists.length Q = Array.indexed(1, k) Q.heap_size = 0 for list_ in lists: if list_.head is not None: x = list_.head list_.head = list_.head.next x.next = None _min_heap_insert_pair(Q, (x, list_)) merged_list = List() tail = None while Q.heap_size > 0: element, list_ = _heap_extract_min_pair(Q) if merged_list.head is None: tail = merged_list.head = element else: tail.next = element tail = tail.next if list_.head is not None: _min_heap_insert_pair(Q, (list_.head, list_)) list_.head = list_.head.next return merged_list
def perfect_hashing_init(K): max_key = max(K) # from Bertrand's postulate, for each n >= 1, there is a prime p, such that n < p <= 2n p = random.choice(list(sieve.primerange(max_key + 1, 2 * max_key + 1))) m = K.length T = Array.indexed(0, m - 1) h = _get_random_universal_hash_function(p, m) mapped_keys = [[] for _ in range(m)] for k in K: mapped_keys[h(k)].append(k) secondary_sizes = [len(keys)**2 for keys in mapped_keys] for j, size in enumerate(secondary_sizes): if size == 1: T[j] = (lambda _: 0, Array([mapped_keys[j][0]], start=0)) elif size > 1: h_ = None S = None while S is None: h_ = _get_random_universal_hash_function(p, size) S = _construct_secondary_hash_table_no_collisions( mapped_keys[j], size, h_) T[j] = (h_, S) return T, h
def test_in_place_chained_hash_table(self): table_size = random.randint(1, 20) keys, _ = get_random_unique_array(max_size=table_size, max_value=99) elements = [Element(key) for key in keys] table = Array.indexed(0, table_size - 1) table.free = 0 for i in range(table_size): table[i] = FreePosition(i - 1, i + 1) table[table_size - 1].next = -1 h = lambda k, m: k % m for element in elements: in_place_chained_hash_insert(table, element, h) for key in range(100): actual_element = in_place_chained_hash_search(table, key, h) if key in keys: assert_that(actual_element.key, is_(equal_to(key))) in_place_chained_hash_delete(table, actual_element, h) else: assert_that(actual_element, is_(none())) assert_in_place_hash_table_clear(table)
def persistent_rb_insert(T, z): path_length = _get_path_length_from_root_to_node(T, z) S = Array.indexed(1, path_length + 1) S.top = 0 y = T.nil x = T.root T_ = RedBlackTree(sentinel=T.nil) y_ = T_.nil push(S, y_) while x is not T.nil: y = x x_ = rb.ParentlessNode.clone(x) if y_ is T_.nil: T_.root = x_ else: if x is y_.left: y_.left = x_ else: y_.right = x_ y_ = x_ push(S, y_) if z.key < x.key: x = x.left else: x = x.right if y is T.nil: T_.root = z else: if z.key < y.key: y_.left = z else: y_.right = z z.left = z.right = T.nil z.color = Red _persistent_rb_insert_fixup(T_, S, z) return T_
def persistent_rb_delete(T, z): T_ = RedBlackTree() T_.root = T_.nil = T.nil if z.left is T.nil or z.right is T.nil: y = z else: y = rb_successor(z, T.nil) path_length = _get_path_length_from_root_to_node(T, y) S = Array.indexed(1, path_length + 1) S.top = 0 p = T.root r = T.nil p_ = r_ = T_.nil push(S, p_) z_ = T.nil while p is not y: p_ = rb.ParentlessNode.clone(p) push(S, p_) if p is z: z_ = p_ if r_ is T_.nil: T_.root = p_ else: if p is r_.left: r_.left = p_ else: r_.right = p_ r = p r_ = p_ if y.key < p.key: p = p.left else: p = p.right if y.left is not T.nil: x = y.left else: x = y.right if y.color == Black: if x is not T.nil: x_ = rb.ParentlessNode.clone(x) else: x_ = T.nil if y is T.root: T_.root = x_ else: if y is r.left: p_.left = x_ else: p_.right = x_ if y is not z: z_.key = y.key z_.data = y.data persistent_rb_delete_fixup(T_, S, x_) else: if y is r.left: p_.left = x else: p_.right = x if y is not z: z_.key = y.key z_.data = y.data return T_
def test_create_empty_array_with_custom_indexes(self): array = Array.indexed(3, 7) assert_that(array.length, is_(equal_to(5))) assert_that(array.start, is_(equal_to(3))) assert_that(array[4], is_(none()))