def _traverse_post_order(tree: HuffmanTree, byte_list: List[int] = None) \
        -> List:
    """
    Traverses a <tree> in post order and appends 1 if it is a leaf,
    0 if it is a node, and other specifications.
    """
    if not tree.is_leaf():
        if byte_list is None:
            byte_list = []

        byte_list = _traverse_post_order(tree.left, byte_list)
        byte_list = _traverse_post_order(tree.right, byte_list)

        if not tree.left.is_leaf():
            byte_list.append(1)
            byte_list.append(tree.left.number)

        if tree.left.is_leaf():
            byte_list.append(0)
            byte_list.append(tree.left.symbol)

        if not tree.right.is_leaf():
            byte_list.append(1)
            byte_list.append(tree.right.number)

        if tree.right.is_leaf():
            byte_list.append(0)
            byte_list.append(tree.right.symbol)

    return byte_list
def tree_to_bytes(tree: HuffmanTree) -> bytes:
    """ Return a bytes representation of the Huffman tree <tree>.
    The representation should be based on the postorder traversal of the tree's
    internal nodes, starting from 0.

    Precondition: <tree> has its nodes numbered.

    >>> tree = HuffmanTree(None, HuffmanTree(3, None, None), \
    HuffmanTree(2, None, None))
    >>> number_nodes(tree)
    >>> list(tree_to_bytes(tree))
    [0, 3, 0, 2]
    >>> left = HuffmanTree(None, HuffmanTree(3, None, None), \
    HuffmanTree(2, None, None))
    >>> right = HuffmanTree(5)
    >>> tree = HuffmanTree(None, left, right)
    >>> number_nodes(tree)
    >>> list(tree_to_bytes(tree))
    [0, 3, 0, 2, 1, 0, 0, 5]
    >>> tree = build_huffman_tree(build_frequency_dict(b"helloworld"))
    >>> number_nodes(tree)
    >>> list(tree_to_bytes(tree)) #doctest: +NORMALIZE_WHITESPACE
    [0, 104, 0, 101, 0, 119, 0, 114, 1, 0, 1, 1, 0, 100, 0, 111, 0, 108,\
    1, 3, 1, 2, 1, 4]
    >>> tree = HuffmanTree(None, HuffmanTree(None, HuffmanTree(10, None, None),\
    HuffmanTree(12, None, None)), \
    HuffmanTree(None, HuffmanTree(5, None, None), HuffmanTree(7, None, None)))
    >>> number_nodes(tree)
    >>> list(tree_to_bytes(tree))
    [0, 10, 0, 12, 0, 5, 0, 7, 1, 0, 1, 1]
    """
    if tree.is_leaf() and tree.symbol is None:
        return bytes([])
    else:
        return bytes(_traverse_post_order(tree))
def get_codes(tree: HuffmanTree) -> Dict[int, str]:
    """ Return a dictionary which maps symbols from the Huffman tree <tree>
    to codes.

    >>> tree = HuffmanTree(None, HuffmanTree(3), HuffmanTree(2))
    >>> d = get_codes(tree)
    >>> d == {3: "0", 2: "1"}
    True
    >>> tree = HuffmanTree(None, None, None)
    >>> d = get_codes(tree)
    >>> d == {}
    True
    >>> left = HuffmanTree(None, HuffmanTree(3), HuffmanTree(2))
    >>> right = HuffmanTree(9)
    >>> tree = HuffmanTree(None, left, right)
    >>> d_test = get_codes(tree)
    >>> d_test == {3: "00", 2: "01", 9: "1"}
    True
    >>> left_ext = HuffmanTree(None, HuffmanTree(2), HuffmanTree(3))
    >>> left = HuffmanTree(None, HuffmanTree(1), left_ext)
    >>> right = HuffmanTree(None, HuffmanTree(9), HuffmanTree(10))
    >>> tree = HuffmanTree(None, left, right)
    >>> d = get_codes(tree)
    >>> d == {1: '00', 2: '010', 3: '011', 9: '10', 10: '11'}
    True
    >>> tree = HuffmanTree(None, HuffmanTree(3), HuffmanTree(2))
    >>> d_text = get_codes(tree)
    >>> d_text
    {3: '0', 2: '1'}
    """
    # Edge Case
    if tree is None or (tree.symbol is None and tree.is_leaf()):
        return {}
    else:
        return _get_codes_helper(tree, "")
def _number_nodes_helper(tree: HuffmanTree, number: int = 0) -> int:
    """
    A helper function that uses a <tree> to <number> the internal nodes.
    """
    if tree.is_leaf():
        return number - 1
    else:
        number = _number_nodes_helper(tree.left, number) + 1
        number = _number_nodes_helper(tree.right, number) + 1
        tree.number = number
        return number
def number_nodes(tree: HuffmanTree) -> None:
    """ Number internal nodes in <tree> according to postorder traversal. The
    numbering starts at 0.

    >>> left = HuffmanTree(None, HuffmanTree(3), HuffmanTree(2))
    >>> right = HuffmanTree(None, HuffmanTree(9), HuffmanTree(10))
    >>> tree = HuffmanTree(None, left, right)
    >>> number_nodes(tree)
    >>> tree.left.number
    0
    >>> tree.right.number
    1
    >>> tree.number
    2
    >>> right_ext = HuffmanTree(None, HuffmanTree(2), HuffmanTree(3))
    >>> left = HuffmanTree(None, HuffmanTree(1), right_ext)
    >>> right = HuffmanTree(None, HuffmanTree(9), HuffmanTree(10))
    >>> tree = HuffmanTree(None, left, right)
    >>> number_nodes(tree)
    >>> tree.left.right.number
    0
    >>> tree.left.number
    1
    >>> tree.right.number
    2
    >>> tree.number
    3
    >>> left_ext = HuffmanTree(None, HuffmanTree(2), HuffmanTree(3))
    >>> left = HuffmanTree(None, left_ext, HuffmanTree(1))
    >>> right = HuffmanTree(None, HuffmanTree(9), HuffmanTree(10))
    >>> tree = HuffmanTree(None, left, right)
    >>> number_nodes(tree)
    >>> tree.left.left.number
    0
    >>> tree.left.number
    1
    >>> tree.right.number
    2
    >>> tree.number
    3
    >>> tree = HuffmanTree(None)
    >>> number_nodes(tree)
    >>> tree.number

    """
    if tree.symbol is None and tree.is_leaf():
        return None
    else:
        _number_nodes_helper(tree, 0)
        return None
Beispiel #6
0
def get_codes(tree: HuffmanTree) -> Dict[int, str]:
    """ Return a dictionary which maps symbols from the Huffman tree <tree>
    to codes.

    >>> tree = HuffmanTree(None, HuffmanTree(3), HuffmanTree(2))
    >>> d = get_codes(tree)
    >>> d == {3: "0", 2: "1"}
    True
    """
    final = {}

    if tree.is_leaf():
        return {tree.symbol: '0'}

    else:
        _traverse_huff(tree, "", final)
        return final
Beispiel #7
0
def _recursive_numbering(tree: HuffmanTree, cur_num: list):
    """
    Algorithm that recursively builds and mutates the huff_map
    """
    if tree.is_leaf():  # dont number leaves
        return

    elif not tree:  # blank tree, graceful termiantion
        return

    else:

        _recursive_numbering(tree.left, cur_num)
        # then right
        _recursive_numbering(tree.right, cur_num)
        # finally root
        tree.number = cur_num[0]
        cur_num[0] += 1
def _get_codes_helper(tree: HuffmanTree, code: str,
                      symbol_dict: Any = None) -> Dict[int, str]:
    """
    A helper function for <get_codes> that returns a dictionary which maps
    symbols from the Huffman tree <tree> to codes <code>, and    outputs
    a dictionary <symbol_dict>.
    """

    if tree.is_leaf():
        symbol_dict[tree.symbol] = code
        return symbol_dict

    else:
        if symbol_dict is None:
            symbol_dict = {}

        symbol_dict = _get_codes_helper(tree.left, code + "0", symbol_dict)
        symbol_dict = _get_codes_helper(tree.right, code + "1", symbol_dict)

    return symbol_dict
def _find_height(tree: HuffmanTree, count: List = None) -> int:
    """
    Returns the height <count> of a <tree>.

    >>> tree = HuffmanTree(None, HuffmanTree(None, \
    HuffmanTree(None, HuffmanTree(104, None, None), \
    HuffmanTree(101, None, None)), HuffmanTree(None, \
    HuffmanTree(119, None, None), HuffmanTree(114, None, None))), \
    HuffmanTree(None, HuffmanTree(108, None, None), \
    HuffmanTree(None, HuffmanTree(100, None, None), \
    HuffmanTree(111, None, None))))
    >>> print(len(_find_height(tree)))
    6
    """
    if not tree.is_leaf():
        if count is None:
            count = []

        _find_height(tree.left, count)
        _find_height(tree.right, count)
        count.append(tree.symbol)

    return count
Beispiel #10
0
def tree_to_bytes(tree: HuffmanTree) -> bytes:
    """ Return a bytes representation of the Huffman tree <tree>.
    The representation should be based on the postorder traversal of the tree's
    internal nodes, starting from 0.

    Precondition: <tree> has its nodes numbered.

    >>> tree = HuffmanTree(None, HuffmanTree(3, None, None), \
    HuffmanTree(2, None, None))
    >>> number_nodes(tree)
    >>> list(tree_to_bytes(tree))
    [0, 3, 0, 2]
    >>> left = HuffmanTree(None, HuffmanTree(3, None, None), \
    HuffmanTree(2, None, None))
    >>> right = HuffmanTree(5)
    >>> tree = HuffmanTree(None, left, right)
    >>> number_nodes(tree)
    >>> list(tree_to_bytes(tree))
    [0, 3, 0, 2, 1, 0, 0, 5]
    >>> tree = build_huffman_tree(build_frequency_dict(b"helloworld"))
    >>> number_nodes(tree)
    >>> list(tree_to_bytes(tree))\
            #doctest: +NORMALIZE_WHITESPACE
    [0, 104, 0, 101, 0, 119, 0, 114, 1, 0, 1, 1, 0, 100, 0, 111, 0, 108,\
    1, 3, 1, 2, 1, 4]
    """
    final = []

    if tree.is_leaf():
        return bytes([0, 0, 0, 0])

    else:
        # user recursive function to post_travers
        _recursive_tree_to_bytes(tree, final)

        return bytes(final)
Beispiel #11
0
def number_nodes(tree: HuffmanTree) -> None:
    """ Number internal nodes in <tree> according to postorder traversal. The
    numbering starts at 0.

    >>> left = HuffmanTree(None, HuffmanTree(3), HuffmanTree(2))
    >>> right = HuffmanTree(None, HuffmanTree(9), HuffmanTree(10))
    >>> tree = HuffmanTree(None, left, right)
    >>> number_nodes(tree)
    >>> tree.left.number
    0
    >>> tree.right.number
    1
    >>> tree.number
    2
    """
    # cant be recursive because different in/out\
    # use list so we can mutate value

    if tree.is_leaf():
        # leafs arent given a number
        tree.number = None

    else:
        _recursive_numbering(tree, [0])