Ejemplo n.º 1
0
            i = next(
                j for j, y in enumerate(path)
                if x > y.val and y.right is None)  # highest insertion point
            while len(path) > i + 1:
                yield path.pop().val
            c = path[-1]  # equivalent to path[i]
            c.right = Node(None, x, None)
            path.append(c.right)
    while len(path) > 0:  # pop everything
        yield path.pop().val


if __name__ == '__main__':
    from lib import fails_as, iter_equals
    from trees.construction import random_bst
    from trees.traversal import pre_order, post_order
    std_test = {
        (40, 30, 35, 80, 100): (35, 30, 100, 80, 40),
        (40, 30, 32, 35, 80, 90, 100, 120): (35, 32, 30, 120, 100, 90, 80, 40),
        (40, 30, 10, 35, 37, 80, 70, 60, 75, 100, 90):
        (10, 37, 35, 30, 60, 75, 70, 90, 100, 80, 40)
    }
    for k, v in std_test.items():
        assert iter_equals(convert(k), v)
    fail_test = {(7, 9, 6, 1, 4, 2, 3, 40), (40, 30, 35, 20, 80, 100)}
    for x in fail_test:
        assert fails_as(AssertionError, lambda y: tuple(convert(y)), x)
    for size in [x for x in range(1, 100) for _ in range(x)]:
        t = random_bst(size)
        assert iter_equals(convert(pre_order(t)), post_order(t))
Ejemplo n.º 2
0
            s.append((x.left, False))


def fast_post_order(root):
    s = [(root, 0)]
    while len(s) > 0:
        x, v = s[
            -1]  # v = 0: left child unvisited; 1: left child visited, but right child not; 2: right child visited
        if x is None:
            s.pop()
            continue
        if v == 0:
            s[-1] = x, 1
            s.append((x.left, 0))
        elif v == 1:
            s[-1] = x, 2
            s.append((x.right, 0))
        else:
            yield x.val
            s.pop()


if __name__ == '__main__':
    from lib import iter_equals
    from trees.construction import random_bst
    for size in range(1, 100):
        t = random_bst(size)
        assert iter_equals(pre_order(t), fast_pre_order(t))
        assert iter_equals(in_order(t), fast_in_order(t))
        assert iter_equals(post_order(t), fast_post_order(t))
Ejemplo n.º 3
0
from collections import deque

def product(*iters, reverse=False):
    """
    Recursion-free implementation of itertools.product with manually managed stack/queue.
    Time complexity is O(\prod n_i), where n_i is the size of each iterator. Space complexity is O(\prod n_i).
    :param iters: *iterable[T]. As in itertools.product, each iterable must be non-empty, otherwise nothing is generated.
    :param reverse: bool. product(..., reverse=True) is equivalent to product(..., reverse=False) with each iterable
        in reverse order. A stack is used instead of a queue for this purpose.
    :return: generator[tuple[*T]].
    """
    n = len(iters)
    q = deque()
    q.append(([], 0))  # deque[tuple[list[T],int]]
    while q:
        xs, i = q.pop() if reverse else q.popleft()
        if i == n:
            yield tuple(xs)
        else:
            for y in iters[i]:
                q.append((xs + [y], i + 1))

if __name__ == '__main__':
    from itertools import product as control
    from lib import iter_equals
    xs = [1, 2], [3, 4, 5], [6, 7, 8, 9]
    assert iter_equals(control(*xs), product(*xs))
    assert iter_equals(list(control(*xs))[::-1], product(*xs, reverse=True))
Ejemplo n.º 4
0
    x, c = pseudo_root, 0
    while x.right is not None:
        x = x.right
        c += 1
    vine_to_tree(pseudo_root, c)
    return pseudo_root.right, c

def max_height_diff(root):
    def step(x):
        if x is None:
            return 0, 0
        l_depth, l_diff = step(x.left)  # recursive call
        r_depth, r_diff = step(x.right)  # recursive call
        depth = max(l_depth, r_depth) + 1
        diff = max(l_diff, r_diff, abs(l_depth - r_depth))
        return depth, diff
    return step(root)[1]

if __name__ == '__main__':
    from lib import iter_equals
    from trees.construction import random_bst
    from trees.traversal import in_order
    for size in [x for x in range(1, 100) for _ in range(x)]:
        t = random_bst(size)
        d = max_height_diff(t)
        control = list(in_order(t))
        r, c = day_stout_warren(t)
        assert c == size
        assert iter_equals(in_order(r), control)
        assert max_height_diff(r) <= d
Ejemplo n.º 5
0
        binary tree.
    Assumes the input is a valid pre-order traversal sequence, and elements in the BST to be unique.
    :param seq: seq[T], where T is comparable
    :return: Node
    """
    ite = iter(seq)
    x = next(ite, None)
    assert x is not None  # empty iterator
    root = Node(None, x, None)
    s = [root]
    for x in ite:  # iterate through seq[1:]
        new = Node(None, x, None)
        if x < s[-1].val:
            s[-1].left = new
        else:  # x > s[-1].val
            while len(s) > 0 and x > s[-1].val:
                last = s.pop()
            last.right = new  # select the highest insertion point
        s.append(new)
    return root

if __name__ == '__main__':
    from lib import iter_equals
    from trees.construction import random_bst
    from trees.traversal import fast_pre_order, in_order, fast_post_order
    for size in [x for x in range(1, 100) for _ in range(x)]:
        t = random_bst(size)
        r = rebuild(fast_pre_order(t))
        assert iter_equals(in_order(r), in_order(t))
        assert iter_equals(fast_post_order(r), fast_post_order(t))
Ejemplo n.º 6
0
from collections import deque


def product(*iters, reverse=False):
    """
    Recursion-free implementation of itertools.product with manually managed stack/queue.
    Time complexity is O(\prod n_i), where n_i is the size of each iterator. Space complexity is O(\prod n_i).
    :param iters: *iterable[T]. As in itertools.product, each iterable must be non-empty, otherwise nothing is generated.
    :param reverse: bool. product(..., reverse=True) is equivalent to product(..., reverse=False) with each iterable
        in reverse order. A stack is used instead of a queue for this purpose.
    :return: generator[tuple[*T]].
    """
    n = len(iters)
    q = deque()
    q.append(([], 0))  # deque[tuple[list[T],int]]
    while q:
        xs, i = q.pop() if reverse else q.popleft()
        if i == n:
            yield tuple(xs)
        else:
            for y in iters[i]:
                q.append((xs + [y], i + 1))


if __name__ == '__main__':
    from itertools import product as control
    from lib import iter_equals
    xs = [1, 2], [3, 4, 5], [6, 7, 8, 9]
    assert iter_equals(control(*xs), product(*xs))
    assert iter_equals(list(control(*xs))[::-1], product(*xs, reverse=True))
Ejemplo n.º 7
0
        c += 1
    vine_to_tree(pseudo_root, c)
    return pseudo_root.right, c


def max_height_diff(root):
    def step(x):
        if x is None:
            return 0, 0
        l_depth, l_diff = step(x.left)  # recursive call
        r_depth, r_diff = step(x.right)  # recursive call
        depth = max(l_depth, r_depth) + 1
        diff = max(l_diff, r_diff, abs(l_depth - r_depth))
        return depth, diff

    return step(root)[1]


if __name__ == '__main__':
    from lib import iter_equals
    from trees.construction import random_bst
    from trees.traversal import in_order
    for size in [x for x in range(1, 100) for _ in range(x)]:
        t = random_bst(size)
        d = max_height_diff(t)
        control = list(in_order(t))
        r, c = day_stout_warren(t)
        assert c == size
        assert iter_equals(in_order(r), control)
        assert max_height_diff(r) <= d
Ejemplo n.º 8
0
            s.append((x.right, False))
        else:
            s[-1] = x, True
            s.append((x.left, False))

def fast_post_order(root):
    s = [(root, 0)]
    while len(s) > 0:
        x, v = s[-1]  # v = 0: left child unvisited; 1: left child visited, but right child not; 2: right child visited
        if x is None:
            s.pop()
            continue
        if v == 0:
            s[-1] = x, 1
            s.append((x.left, 0))
        elif v == 1:
            s[-1] = x, 2
            s.append((x.right, 0))
        else:
            yield x.val
            s.pop()

if __name__ == '__main__':
    from lib import iter_equals
    from trees.construction import random_bst
    for size in range(1, 100):
        t = random_bst(size)
        assert iter_equals(pre_order(t), fast_pre_order(t))
        assert iter_equals(in_order(t), fast_in_order(t))
        assert iter_equals(post_order(t), fast_post_order(t))
Ejemplo n.º 9
0
        if x < c.val:  # x is either the left child of cursor, or is an invalid input
            for y in path[:-1]:  # insert x from the root. it should arrive at cursor
                assert x > y.val or y.left is not None
            c.left = Node(None, x, None)
            path.append(c.left)
        else:  # x is either the right child of cursor, or a right child of an ancestor of cursor
            i = next(j for j, y in enumerate(path) if x > y.val and y.right is None)  # highest insertion point
            while len(path) > i + 1:
                yield path.pop().val
            c = path[-1]  # equivalent to path[i]
            c.right = Node(None, x, None)
            path.append(c.right)
    while len(path) > 0:  # pop everything
        yield path.pop().val

if __name__ == '__main__':
    from lib import fails_as, iter_equals
    from trees.construction import random_bst
    from trees.traversal import pre_order, post_order
    std_test = {(40, 30, 35, 80, 100): (35, 30, 100, 80, 40),
                (40, 30, 32, 35, 80, 90, 100, 120): (35, 32, 30, 120, 100, 90, 80, 40),
                (40, 30, 10, 35, 37, 80, 70, 60, 75, 100, 90): (10, 37, 35, 30, 60, 75, 70, 90, 100, 80, 40)}
    for k, v in std_test.items():
        assert iter_equals(convert(k), v)
    fail_test = {(7, 9, 6, 1, 4, 2, 3, 40), (40, 30, 35, 20, 80, 100)}
    for x in fail_test:
        assert fails_as(AssertionError, lambda y: tuple(convert(y)), x)
    for size in [x for x in range(1, 100) for _ in range(x)]:
        t = random_bst(size)
        assert iter_equals(convert(pre_order(t)), post_order(t))
Ejemplo n.º 10
0
            # since __bool__ is not defined in Link, bool(link) is always True unless link is None
            yield y.key

def remove_duplicates(head):  # in-place, O(n^2) time
    left = head
    while left is not None:
        probe = left  # inspect probe.right
        while probe is not None:
            if probe.right is not None and probe.right.key == left.key:
                probe.right = probe.right.right
            else:  # if probe.right is removed, then do not move forward. consider [0, -6, 7, 4, 5, -6, -6]
                probe = probe.right
        left = left.right

if __name__ == '__main__':
    from lib import iter_equals
    from random import randint
    def control(arr):
        appeared = set()
        for x in arr:
            if x not in appeared:
                yield x
            appeared.add(x)
    for size in [x for x in range(50) for _ in range(x)]:
        a = [randint(-size, size) for _ in range(size)]
        ll = LinkedList(reversed(a))
        ll.reverse()
        assert iter_equals(ll, a)
        remove_duplicates(ll.head)
        assert iter_equals(ll, control(a))