## Recursive Objects ## # Q2 def list_to_link(lst): """Takes a Python list and returns a Link with the same elements. >>> link = list_to_link([1, 2, 3]) >>> print(link) <1 2 3> """ "*** YOUR CODE HERE ***" # Q3 def link_to_list(link): """Takes a Link and returns a Python list with the same elements. >>> link = Link(1, Link(2, Link(3, Link(4)))) >>> link_to_list(link) [1, 2, 3, 4] >>> link_to_list(Link.empty) [] """ "*** YOUR CODE HERE ***" # Q4 def remove_all(link , value): """Remove all the nodes containing value. Assume there exists some nodes to be removed and the first element is never removed. >>> l1 = Link(0, Link(2, Link(2, Link(3, Link(1, Link(2, Link(3))))))) >>> print(l1) <0 2 2 3 1 2 3> >>> remove_all(l1, 2) >>> print(l1) <0 3 1 3> >>> remove_all(l1, 3) >>> print(l1) <0 1> """ "*** YOUR CODE HERE ***" # Linked List Class class Link: """A linked list. >>> s = Link(1, Link(2, Link(3))) >>> s.first 1 >>> s.rest Link(2, Link(3)) """ empty = () def __init__(self, first, rest=empty): assert rest is Link.empty or isinstance(rest, Link) self.first = first self.rest = rest def __repr__(self): if self.rest is Link.empty: return 'Link({})'.format(self.first) else: return 'Link({}, {})'.format(self.first, repr(self.rest)) def __str__(self): """Returns a human-readable string representation of the Link >>> s = Link(1, Link(2, Link(3, Link(4)))) >>> str(s) '<1 2 3 4>' >>> str(Link(1)) '<1>' >>> str(Link.empty) # empty tuple '()' """ string = '<' while self.rest is not Link.empty: string += str(self.first) + ' ' self = self.rest return string + str(self.first) + '>' def __len__(self): """ Return the number of items in the linked list. >>> s = Link(1, Link(2, Link(3))) >>> len(s) 3 >>> s = Link.empty >>> len(s) 0 """ return 1 + len(self.rest) def __getitem__(self, i): """Returning the element found at index i. >>> s = Link(1, Link(2, Link(3))) >>> s[1] 2 >>> s[2] 3 """ if i == 0: return self.first else: return self.rest[i-1] def __setitem__(self, index, element): """Sets the value at the given index to the element >>> s = Link(1, Link(2, Link(3))) >>> s[1] = 5 >>> s Link(1, Link(5, Link(3))) >>> s[4] = 5 Traceback (most recent call last): ... IndexError """ if index == 0: self.first = element elif self.rest is Link.empty: raise IndexError else: self.rest[index - 1] = element def __contains__(self, e): return self.first == e or e in self.rest def map(self, f): self.first = f(self.first) if self.rest is not Link.empty: self.rest.map(f) # Tree Class class Tree: def __init__(self, label, branches=[]): for c in branches: assert isinstance(c, Tree) self.label = label self.branches = list(branches) def __repr__(self): if self.branches: branches_str = ', ' + repr(self.branches) else: branches_str = '' return 'Tree({0}{1})'.format(self.label, branches_str) def is_leaf(self): return not self.branches def __eq__(self, other): return type(other) is type(self) and self.label == other.label \ and self.branches == other.branches 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() def copy_tree(self): return Tree(self.label, [b.copy_tree() for b in self.branches])