CSC111 / lectures / recursive tree.py
recursive tree.py
Raw
from __future__ import annotations
from typing import Any, Optional


class Tree:
    """A recursive tree data structure.

    Representation Invariants:
        - self._root is not None or self._subtrees == []
    """
    # Private Instance Attributes:
    #   - _root:
    #       The item stored at this tree's root, or None if the tree is empty.
    #   - _subtrees:
    #       The list of subtrees of this tree. This attribute is empty when
    #       self._root is None (representing an empty tree). However, this attribute
    #       may be empty when self._root is not None, which represents a tree consisting
    #       of just one item.
    _root: Optional[Any]
    _subtrees: list[Tree]

    def __init__(self, root: Optional[Any], subtrees: list[Tree]) -> None:
        """Initialize a new Tree with the given root value and subtrees.

        If root is None, the tree is empty.

        Preconditions:
            - root is not none or subtrees == []
        """
        self._root = root
        self._subtrees = subtrees

    def is_empty(self) -> bool:
        """Return whether this tree is empty.
        """
        return self._root is None

    def first_at_depth(self, d: int) -> Optional[Any]:
        """Return the leftmost value at depth d in this tree.

        Return None if there are NO items at depth d in this tree.

        Preconditions:
            - d >= 0
        """
        if self.is_empty():
            return None
        elif self._subtrees == []:
            if d == 0:
                return self._root
            else:
                return None
        else:
            if d == 0:
                return self._root
            for subtree in self._subtrees:
                rec_value = subtree.first_at_depth(d - 1)
                if rec_value is not None:
                    return rec_value
            return None

    # def __str__(self) -> str:
    def _str_helper(self, depth) -> str:
        if self.is_empty():
            return ''
        else:
            indentation = depth * ' '
            str_so_far = indentation + f'{self._root}\n'
            for subtree in self._subtrees:
                str_so_far += subtree._str_helper(depth + 1)
            return str_so_far