【CS 61a study notes 4】Tree & Iterator & Generator

Tree

We often use recursion to solve Tree problem .The main idea is , we peel off the label of the tree to find the base case , and then use for-statement to apply the function to all branches.

Tree data abstraction


# Tree ADT

def tree(label, branches=[]):
    """Construct a tree with the given label value and a list of branches."""
    for branch in branches:
        assert is_tree(branch), 'branches must be trees'
    return [label] + list(branches)

def label(tree):
    """Return the label value of a tree."""
    return tree[0]

def branches(tree):
    """Return the list of branches of the given tree."""
    return tree[1:]

def is_tree(tree):
    """Returns True if the given tree is a tree, and False otherwise."""
    if type(tree) != list or len(tree) < 1:
        return False
    for branch in branches(tree):
        if not is_tree(branch):
            return False
    return True

def is_leaf(tree):
    """Returns True if the given tree's list of branches is empty, and False
    otherwise.
    """
    return not branches(tree)

def print_tree(t, indent=0):
    """Print a representation of this tree in which each node is
    indented by two spaces times its depth from the root.

    >>> print_tree(tree(1))
    1
    >>> print_tree(tree(1, [tree(2)]))
    1
      2
    >>> numbers = tree(1, [tree(2), tree(3, [tree(4), tree(5)]), tree(6, [tree(7)])])
    >>> print_tree(numbers)
    1
      2
      3
        4
        5
      6
        7
    """
    print('  ' * indent + str(label(t)))
    for b in branches(t):
        print_tree(b, indent + 1)

def copy_tree(t):
    """Returns a copy of t. Only for testing purposes.

    >>> t = tree(5)
    >>> copy = copy_tree(t)
    >>> t = tree(6)
    >>> print_tree(copy)
    5
    """
    return tree(label(t), [copy_tree(b) for b in branches(t)])


class Tree


class Tree:
    """
    >>> t = Tree(3, [Tree(2, [Tree(5)]), Tree(4)])
    >>> t.label
    3
    >>> t.branches[0].label
    2
    >>> t.branches[1].is_leaf()
    True
    """
    def __init__(self, label, branches=[]):
        for b in branches:
            assert isinstance(b, Tree)
        self.label = label
        self.branches = list(branches)

    def is_leaf(self):
        return not self.branches

    def map(self, fn):
        """
        Apply a function `fn` to each node in the tree and mutate the tree.

        >>> t1 = Tree(1)
        >>> t1.map(lambda x: x + 2)
        >>> t1.map(lambda x : x * 4)
        >>> t1.label
        12
        >>> t2 = Tree(3, [Tree(2, [Tree(5)]), Tree(4)])
        >>> t2.map(lambda x: x * x)
        >>> t2
        Tree(9, [Tree(4, [Tree(25)]), Tree(16)])
        """
        self.label = fn(self.label)
        for b in self.branches:
            b.map(fn)

    def __contains__(self, e):
        """
        Determine whether an element exists in the tree.

        >>> t1 = Tree(1)
        >>> 1 in t1
        True
        >>> 8 in t1
        False
        >>> t2 = Tree(3, [Tree(2, [Tree(5)]), Tree(4)])
        >>> 6 in t2
        False
        >>> 5 in t2
        True
        """
        if self.label == e:
            return True
        for b in self.branches:
            if e in b:
                return True
        return False

    def __repr__(self):
        if self.branches:
            branch_str = ', ' + repr(self.branches)
        else:
            branch_str = ''
        return 'Tree({0}{1})'.format(self.label, branch_str)

    def __str__(self):
        def print_tree(t, indent=0):
            tree_str = '  ' * indent + str(t.label) + "\n"
            for b in t.branches:
                tree_str += print_tree(b, indent + 1)
            return tree_str
        return print_tree(self).rstrip()

hw03

mobile data abstraction


'''
We are making a planetarium mobile.
A mobile is a type of hanging sculpture.A binary mobile consists of two arms.Each arm is a rod of a certain length, from which hangs either a planet or another mibile.

We will represent a binary mobile using data abstructions below:
    A mobile must have both a left arm and a right arm
    An arm has a positive length and must have something hanging at the end ,either a mobile or a planet
    A planet has a positive size ,and nothing hanging from it 
    
Arms-length recursion(sidenote)
def min_depth(t):
    """ A simple function to return the distance between t's root and its closest leaf"""
    if is_leaf(t):
        return 0 # Base case--the distance between a node and itself is 0
    h = float('inf') #Python's version of infinity
    for b in branches(t):
        if is_leaf(b):
            return 1 #!!!
        h = min(h,1+min_depth(b))
    return h
    
The line flagged with !!! is an "arms-length" recursion violation.
Although our code works correctly when it is present,by performing this check we are doing work that should be done by the next level of recursion -- we already have an if-statement that handles any inputs to min_depth that are leaves, so we should not include this line to eliminate redundancy in our code.


def min_depth(t):
    if is_leaf(t):
        return 0
    
    h = float('inf')
    
    for b in branches(t):
        h = min(h,1 +min_depth(b))
    return h
    
Arm-length recursion is not only redundant but often complicates our code and obscures the functionality of the recursive functions,making writing recursive functions much more difficult.     
   
'''

def mobile(left, right):
    """Construct a mobile from a left arm and a right arm."""
    assert is_arm(left), "left must be a arm"
    assert is_arm(right), "right must be a arm"
    return ['mobile', left, right]

def is_mobile(m):
    """Return whether m is a mobile."""
    return type(m) == list and len(m) == 3 and m[0] == 'mobile'

def left(m):
    """Select the left arm of a mobile."""
    assert is_mobile(m), "must call left on a mobile"
    return m[1]

def right(m):
    """Select the right arm of a mobile."""
    assert is_mobile(m), "must call right on a mobile"
    return m[2]

def arm(length, mobile_or_planet):
    """Construct a arm: a length of rod with a mobile or planet at the end."""
    assert is_mobile(mobile_or_planet) or is_planet(mobile_or_planet)
    return ['arm', length, mobile_or_planet]

def is_arm(s):
    """Return whether s is a arm."""
    return type(s) == list and len(s) == 3 and s[0] == 'arm'

def length(s):
    """Select the length of a arm."""
    assert is_arm(s), "must call length on a arm"
    return s[1]

def end(s):
    """Select the mobile or planet hanging at the end of a arm."""
    assert is_arm(s), "must call end on a arm"
    return s[2]

def planet(size):
    """Construct a planet of some size.
    Implementing the planet data abstraction by completing the planet constructor and the size selector so that the plant is represented using a two element list where the first element is the string 'planet' and the second element is the size.
    The total_weight example is provided to demonstrate use of the mobile,arm,and planet abstraction
    """
    assert size > 0
    "*** YOUR CODE HERE ***"
    return ['planet',size]
    

def size(w):
    """Select the size of a planet."""
    assert is_planet(w), 'must call size on a planet'
    "*** YOUR CODE HERE ***"
    return w[1]
    

def is_planet
### Python GeneratorIterator 的概念 在 Python 中,可迭代对象(Iterable)、生成器(Generator)和迭代器(Iterator)有着不同的角色与功能。 #### Iterable 对象 一个实现了 `__iter__()` 方法的对象被称为可迭代对象。这个方法返回一个迭代器实例[^1]。当调用内置函数 `iter()` 并传入一个列表或其他类型的序列时,会创建相应的迭代器对象[^3]。 #### Iterator 迭代器 迭代器是一个可以记住遍历位置的对象,并且必须实现两个特殊的方法:`__next__()`, 它负责返回下一个元素;以及前面提到过的 `__iter__()`. 当没有更多数据可供读取的时候,则抛出 StopIteration 异常来通知结束循环[^4]. ```python class MyIterator: def __init__(self, data): self.data = data self.index = 0 def __iter__(self): return self def __next__(self): if self.index &gt;= len(self.data): raise StopIteration result = self.data[self.index] self.index += 1 return result ``` #### Generator 生成器 生成器是一种特殊的迭代器,在定义上更加简洁高效。通过含有 yield 表达式的函数创建而成。每当执行到 yield 关键字处就会暂停并保存当前状态直到下一次被唤醒继续运行下去[^2]. 使用这种方式编写的代码不仅易于理解而且占用更少内存资源因为它们按需生产值而不是一次性全部加载进内存中. ```python def my_generator(): value = &#39;first&#39; yield value value = &#39;second&#39; yield value value = &#39;third&#39; yield value ``` ### 区别与联系 - **创建方式**: 虽然两者都可以用于逐个访问集合内的成员,但是生成器通常由带有 yield 语句的函数构成而不需要显式地编写类去继承特定接口. - **性能表现**: 由于生成器只会在请求到来之时才计算所需的结果所以对于处理大数据集来说效率更高也更为节省空间复杂度. - **灵活性**: 尽管如此,如果想要自定义一些额外的行为比如重置计数器或是支持双向移动指针那么还是应该考虑基于传统意义上的迭代器模式来进行设计.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值