[2021 Spring] CS61A 學習筆記 Homework 5: Object-Oriented Programming, Linked Lists, Iterators and Generators


作業說明: https://inst.eecs.berkeley.edu/~cs61a/sp21/hw/hw05/

Q1: 自動售貨機

根據doctests添加類的屬性和方法。創建類時傳遞商品名稱和價格,庫存和已投幣金額初始化為0。
注意:

  1. 不要使用print,使用return才會返回字符串,格式轉化可使用 f''。
  2. 成功售賣后,庫存減一、 金額置零。
class VendingMachine:
    """A vending machine that vends some product for some price.

    >>> v = VendingMachine('candy', 10)
    >>> v.vend()
    'Inventory empty. Restocking required.'
    >>> v.add_funds(15)
    'Inventory empty. Restocking required. Here is your $15.'
    >>> v.restock(2)
    'Current candy stock: 2'
    >>> v.vend()
    'You must add $10 more funds.'
    >>> v.add_funds(7)
    'Current balance: $7'
    >>> v.vend()
    'You must add $3 more funds.'
    >>> v.add_funds(5)
    'Current balance: $12'
    >>> v.vend()
    'Here is your candy and $2 change.'
    >>> v.add_funds(10)
    'Current balance: $10'
    >>> v.vend()
    'Here is your candy.'
    >>> v.add_funds(15)
    'Inventory empty. Restocking required. Here is your $15.'

    >>> w = VendingMachine('soda', 2)
    >>> w.restock(3)
    'Current soda stock: 3'
    >>> w.restock(3)
    'Current soda stock: 6'
    >>> w.add_funds(2)
    'Current balance: $2'
    >>> w.vend()
    'Here is your soda.'
    """
    "*** YOUR CODE HERE ***"

代碼

class VendingMachine:

    def __init__(self, product, price):
        self.product = product
        self.price = price
        self.funds = 0
        self.inventory = 0
    
    def vend(self):
        if self.inventory == 0:
            return f'Inventory empty. Restocking required.'
        else:
            if  self.funds < self.price:
                return f'You must add ${self.price - self.funds} more funds.'
            elif self.funds == self.price:
                self.funds = 0
                self.inventory -= 1
                return f'Here is your {self.product}.'
            else:
                fund = self.funds
                self.funds = 0
                self.inventory -= 1
                return f'Here is your {self.product} and ${fund - self.price} change.'
        
    
    def add_funds(self, balance):
        self.funds += balance
        if self.inventory == 0:
            fund = self.funds
            self.funds = 0
            return f'Inventory empty. Restocking required. Here is your ${fund}.'
        else:
            return f'Current balance: ${self.funds}'
    
    def restock(self, stock):
        self.inventory += stock
        return f'Current {self.product} stock: {self.inventory}'

Q2: Store Digits

循環獲得數字n的最后一位,添加到當前鏈表的頭部。

def store_digits(n):
    """Stores the digits of a positive number n in a linked list.

    >>> s = store_digits(1)
    >>> s
    Link(1)
    >>> store_digits(2345)
    Link(2, Link(3, Link(4, Link(5))))
    >>> store_digits(876)
    Link(8, Link(7, Link(6)))
    >>> # a check for restricted functions
    >>> import inspect, re
    >>> cleaned = re.sub(r"#.*\\n", '', re.sub(r'"{3}[\s\S]*?"{3}', '', inspect.getsource(store_digits)))
    >>> print("Do not use str or reversed!") if any([r in cleaned for r in ["str", "reversed"]]) else None
    """
    "*** YOUR CODE HERE ***"

代碼

def store_digits(n):
    res = Link.empty
    while n > 0:
        rem = n % 10
        res = Link(rem, res)
        n //= 10
    return res

Q3: Yield Paths

  1. t.label == value時,返回[value];
  2. t.label != value時,for循環遍歷樹枝,使用path_yielder遞歸查找;只有當1中生成[value]時,將上一層的t.label與當前path結合。
  3. 對於t1 = Tree(1, [Tree(2, [Tree(3), Tree(4, [Tree(6)]), Tree(5)]), Tree(5)]),next(path_yielder(t1, 6))調用過程:t.label == 6,生成器返回 [6],上一層數t.label =4,for循環內生成[4, 6],依次往上直到根節點。
def path_yielder(t, value):
    """Yields all possible paths from the root of t to a node with the label value
    as a list.

    >>> t1 = Tree(1, [Tree(2, [Tree(3), Tree(4, [Tree(6)]), Tree(5)]), Tree(5)])
    >>> print(t1)
    1
      2
        3
        4
          6
        5
      5
    >>> next(path_yielder(t1, 6))
    [1, 2, 4, 6]
    >>> path_to_5 = path_yielder(t1, 5)
    >>> sorted(list(path_to_5))
    [[1, 2, 5], [1, 5]]

    >>> t2 = Tree(0, [Tree(2, [t1])])
    >>> print(t2)
    0
      2
        1
          2
            3
            4
              6
            5
          5
    >>> path_to_2 = path_yielder(t2, 2)
    >>> sorted(list(path_to_2))
    [[0, 2], [0, 2, 1, 2]]
    """

    "*** YOUR CODE HERE ***"

    for _______________ in _________________:
        for _______________ in _________________:

            "*** YOUR CODE HERE ***"

代碼

def path_yielder(t, value):
    "*** YOUR CODE HERE ***"
    if t.label == value:
        yield [value]
    for b in t.branches:
        for path in path_yielder(b, value):
            "*** YOUR CODE HERE ***"
            yield [t.label] + path

Q4: Mint 鑄幣廠

鑄幣廠類,輸出所制造的硬幣年份和價值。

  1. 每個Mint實例有一個年份戳year。update方法將Mint類的current_year參數更新到self.year。
  2. create方法根據Coin種類kind創建一個實例,年份為self.year(與未更新的Mint.current_year可能不同)。
  3. Coin的worth方法返回硬幣的價值,硬幣的價值等於硬幣面值+(已產出年限-50),注意已產出年限不超過50時,硬幣價值等於面值。
class Mint:
    """A mint creates coins by stamping on years.

    The update method sets the mint's stamp to Mint.current_year.

    >>> mint = Mint()
    >>> mint.year
    2020
    >>> dime = mint.create(Dime)
    >>> dime.year
    2020
    >>> Mint.current_year = 2100  # Time passes
    >>> nickel = mint.create(Nickel)
    >>> nickel.year     # The mint has not updated its stamp yet
    2020
    >>> nickel.worth()  # 5 cents + (80 - 50 years)
    35
    >>> mint.update()   # The mint's year is updated to 2100
    >>> Mint.current_year = 2175     # More time passes
    >>> mint.create(Dime).worth()    # 10 cents + (75 - 50 years)
    35
    >>> Mint().create(Dime).worth()  # A new mint has the current year
    10
    >>> dime.worth()     # 10 cents + (155 - 50 years)
    115
    >>> Dime.cents = 20  # Upgrade all dimes!
    >>> dime.worth()     # 20 cents + (155 - 50 years)
    125
    """
    current_year = 2020

代碼

class Mint:
    current_year = 2020

    def __init__(self):
        self.update()

    def create(self, kind):
        "*** YOUR CODE HERE ***"
        return kind(self.year)

    def update(self):
        "*** YOUR CODE HERE ***"
        self.year = self.current_year

class Coin:
    def __init__(self, year):
        self.year = year

    def worth(self):
        "*** YOUR CODE HERE ***"
        if self.year == Mint.current_year: 
            return self.cents
        else:
            return self.cents + Mint.current_year - self.year - 50

class Nickel(Coin):
    cents = 5

class Dime(Coin):
    cents = 10

Q5: Is BST 二叉搜索樹

有效binary search tree:

  • 每個節點最多有兩個子節點(葉節點本身即是有效bst)
  • 每個子節點都是有效bst
  • 對於每個節點,左子節點的值都小於等於該節點的值
  • 對於每個節點,右子節點的值都大於該節點的值

注意:當node只有一個child時,可以把child當作左右任一邊。
輔助函數:bst_min和bst_max,返回左右子樹的最小值和最大值。

def is_bst(t):
    """Returns True if the Tree t has the structure of a valid BST.

    >>> t1 = Tree(6, [Tree(2, [Tree(1), Tree(4)]), Tree(7, [Tree(7), Tree(8)])])
    >>> is_bst(t1)
    True
    >>> t2 = Tree(8, [Tree(2, [Tree(9), Tree(1)]), Tree(3, [Tree(6)]), Tree(5)])
    >>> is_bst(t2)
    False
    >>> t3 = Tree(6, [Tree(2, [Tree(4), Tree(1)]), Tree(7, [Tree(7), Tree(8)])])
    >>> is_bst(t3)
    False
    >>> t4 = Tree(1, [Tree(2, [Tree(3, [Tree(4)])])])
    >>> is_bst(t4)
    True
    >>> t5 = Tree(1, [Tree(0, [Tree(-1, [Tree(-2)])])])
    >>> is_bst(t5)
    True
    >>> t6 = Tree(1, [Tree(4, [Tree(2, [Tree(3)])])])
    >>> is_bst(t6)
    True
    >>> t7 = Tree(2, [Tree(1, [Tree(5)]), Tree(4)])
    >>> is_bst(t7)
    False
    """
    "*** YOUR CODE HERE ***"

代碼

def is_bst(t):
    "*** YOUR CODE HERE ***"
    def bst_min(t):
        if t.is_leaf(): return t.label
        return min(t.label, bst_min(t.branches[0]))

    def bst_max(t):
        if t.is_leaf(): return t.label
        return max(t.label, bst_max(t.branches[-1]))
    
    if t.is_leaf(): return True
    if len(t.branches) == 1:
        child = t.branches[0]
        return is_bst(child) and \
            (bst_max(child) <= t.label or bst_min(child) > t.label)
    elif len(t.branches) == 2:
        left_child, right_child = t.branches
        return is_bst(left_child) and is_bst(right_child) and \
            bst_max(left_child) <= t.label and bst_min(right_child) > t.label
    else:
        return False

Q6: Preorder

for循環遍歷樹枝即可

def preorder(t):
    """Return a list of the entries in this tree in the order that they
    would be visited by a preorder traversal (see problem description).

    >>> numbers = Tree(1, [Tree(2), Tree(3, [Tree(4), Tree(5)]), Tree(6, [Tree(7)])])
    >>> preorder(numbers)
    [1, 2, 3, 4, 5, 6, 7]
    >>> preorder(Tree(2, [Tree(4, [Tree(6)])]))
    [2, 4, 6]
    """
    "*** YOUR CODE HERE ***"

代碼

def preorder(t):
    "*** YOUR CODE HERE ***"
    if t.is_leaf():
        return [t.label]
    res = []
    for b in t.branches:
        res += preorder(b)
    return [t.label] + res

Q7: Generate Preorder

注意yield from 用法

def generate_preorder(t):
    """Yield the entries in this tree in the order that they
    would be visited by a preorder traversal (see problem description).

    >>> numbers = Tree(1, [Tree(2), Tree(3, [Tree(4), Tree(5)]), Tree(6, [Tree(7)])])
    >>> gen = generate_preorder(numbers)
    >>> next(gen)
    1
    >>> list(gen)
    [2, 3, 4, 5, 6, 7]
    """
    "*** YOUR CODE HERE ***"

代碼

def generate_preorder(t):
    "*** YOUR CODE HERE ***"
    yield t.label
    for b in t.branches:
        yield from generate_preorder(b)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM