#! /usr/bin/python3.4 # ******************************************************** # CS 200 HW #4 DUE Monday, 10/30/2023 at 11:59 pm # via the submit system on the Zoo # ******************************************************** # Name: # Email address: # ******************************************************** # This file may be opened in Python 3 # Lines beginning with hashes are comments. # If you are asked to write a procedure, please make sure it has # the specified name, and the specified number and order of arguments. # The names of the formal arguments need not be the same # as in the problem specification. # For each problem, the intended inputs to your procedures # are specified (for example, "positive integers") # and your procedures need not do anything reasonable # for other possible inputs. # You may write auxiliary procedures in addition to # the requested one(s) -- for each of your auxiliary # procedures, please include a comment explaining # what it does, and giving an example or two. # You may also use procedures you have written # elsewhere in this assignment or previous assignments. # They only need to be defined once somewhere within this file. # Reading: Learning Python, Chapters 26 - 32 # Reading: Python Cookbook, Chapter 8 # Algorithm Design Manual, Steven Skiena # https://link.springer.com/book/10.1007%2F978-1-84800-070-4 # ******************************************************** # ** problem 0 ** (1 easy point) # Replace the number 0 in the definition below to indicate # the number of hours you spent doing this assignment # Decimal numbers (eg, 6.237) are fine. Exclude time # spent reading. def hours(): return 0 # ******************************************************** # ** problem 00 ** (1 fairly easy point) # Below is a UNIX transcript with one command replaced by XXXX transcript = ''' bash-4.4$ pwd /home/accts/sbs5/cs200/hws/answers/x bash-4.4$ echo hello world > world bash-4.4$ xxxx bash-4.4$ ls -l total 0 -rw-rw-r-- 1 sbs5 cs200ta 12 Feb 10 15:46 world -rw-rw-r-- 1 sbs5 cs200ta 12 Feb 10 15:46 World bash-4.4$ diff world world bash-4.4$ diff world World 1c1 < hello world --- > Hello World ''' # define xxxx below to be the correct UNIX command. def xxxx(): return "correct unix command" # ******************************************************** # In this assignment you will create a number of data structures: # ## A common use of classes is to implement data structures. ## This is an example of a stack, ## which is a LIFO - last in first out - structure. ## It is a collection. ## Items are added to the stack with push and removed with pop. ## ----------------------------------------------------------- ## We will see that the python virtual machine for interpreting ## byte code is based on a stack architecture. ## ----------------------------------------------------------- class stack: def __init__(self,stuff=[]): self.items = stuff[:] self.size = len(stuff) def __repr__(self): return "stack({})".format(list(self.items)) def isempty(self): return self.items == [] def push(self, item): self.items.append(item) self.size += 1 def peek(self): if self.isempty(): return "Error: stack is empty" else: return self.items[-1] def pop(self): if self.isempty(): return "Error: stack is empty" else: self.size -= 1 return self.items.pop() ## swap the top two items in the stack def rotate(self): if self.size < 2: return "Error: stack has fewer than 2 elements" else: self.items[-1], self.items[-2] = self.items[-2], self.items[-1] ## define the iterator for stack. Used in for or list comprehension def __iter__(self): """Return iterator for the stack.""" if self.isempty(): return None else: index = self.size -1 while index >= 0: yield self.items[index] index -= 1 ## overload equality operator. def __eq__(self, other): if type(other) != type(self): return False if self.items == other.items: return True else: return False # copy constructor - clone the current instance def copy(self): s = stack(self.items) return s ''' s = stack() s.push(1) s.push(2) s.push(3) s.push(4) ''' ## test the iterator def itest(s): for i in s: print (i) return [x for x in s] ## revstr uses a stack to reverse a string ## ---------------------------------------- def revstr(str): s = stack() for c in str: s.push(c) result = [] while (not s.isempty()): result.append(s.pop()) return ''.join(result) # ******************************************************** # ** problem 1 ** (8 points) # # Write a procedure balanced(string) that reads string, and determines # whether its parentheses are "balanced." Hint: for left delimiters, # push onto stack; for right delimiters, pop from stack and check # whether popped element matches right delimiter. def balanced(string): pass # ******************************************************** # ** problem 2 ** (10 points) # ## Write a queue data structure, similar to the stack above. ## Whereas a stack is LIFO (last in first out), a queue is ## FIFO = first in, first out ## See Skiena, page 71 class queue: def __init__(self, stuff=[]): pass def __str__(self): pass def __repr__(self): pass # is the queue empty? true or false def isempty(self): pass # add an item to queue def enqueue(self, item): pass # remove next item. error message if queue is empty def dequeue(self): pass # return the next item without removing it. # return error message if queue is empty def peek(self): pass ## define the iterator for queue. Used in for or list comprehension ## similar to iterator for stack. def __iter__(self): pass ## overload equality operator. def __eq__(self, other): pass # copy constructor - clone the current instance def copy(self): pass # ******************************************************** # ** problem 3 ** (10 points) ## create a queue using two stacks: s1 and s2 ## enqueue() pushes items on s1 ## dequeue() pop's s2, unless s2 is empty, in which case ## keep popping s1 onto s2 until s1 is empty. Then pop s2 ## peek is similar to dequeue, except no final pop class queue2: # initialize stacks def __init__(self, stuff1 = [], stuff2 = []): self.s1 = stack(stuff1[:]) self.s2 = stack(stuff2[:]) def __str__(self): pass def __repr__(self): pass # is the queue empty? true or false def isempty(self): return self.s1.isempty() and self.s2.isempty() # add an item to queue def enqueue(self, item): pass # remove next item. error message if queue is empty def dequeue(self): pass # return the next item without removing it. # return error message if queue is empty def peek(self): pass ## define the iterator for queue2. Used in for or list comprehension ## HINT: ## convert stacks to lists. ## extend the stack 2 list with the reverse of the stack 1 list ## use a for loop to iterate through the extended list, yielding the item def __iter__(self): pass ## overload equality operator ## true if both stacks are respectively equal ## use the convert stacks to list method given above for __iter__ def __eq__(self, other): pass # copy constructor - clone the current instance def copy(self): pass # ******************************************************** # ** problem 4 ** (10 points) # Write a procedure to reverse a queue. # It should work with either q implementation. def reverseq(q): pass # ******************************************************** # ** problem 5 ** (20 points) ## Reading: Skiena pages 89-93 # Create a hash table. # It will be a list of size buckets. # Each bucket will itself contain a list. # If two items fall in the same bucket, # the respective list will contain both items. # See Skiena page 89 class myhash: def __init__(self, size = 20): pass def __repr__(self): pass def __str__(self): pass # is the hash table empty? def isempty(self): return self.count == 0 # add an item with the given key and value # if there is already an item with the given key, remove it. # no duplicate keys def put(self, key, value): pass # Retrieve the value for the given key. def get(self,key): pass # Remove the item for the given key. def remove(self,key): pass ## Create a hash function using the djb2 algorithm. ## http://www.cse.yorku.ca/~oz/hash.html ## If the optional debug parameter is true, ## print out the value of the hash. def hashfun(self,key, debug=False): pass ## Iterate through the buckets and their respective contents. def __iter__(self): pass ## overload equality operator def __eq__(self, other): pass # copy constructor - clone the current instance def copy(self): pass ''' h = myhash(20) h.put("one",1) h.put("two",2) h.put("three",3) ''' # ******************************************************** # ** problem 6 ** (10 points) # Use your hash function to implement remove duplicates for strings. def removedups(string): pass # ******************************************************** # ** problem 7 ** (20 points) ## Reading: Skiena pages 109-115 # Implement a heap per the description in Skiena. class heap: def __init__(self, size = 10): pass def __str__(self): pass def __repr__(self): pass def isempty(self): pass # Add a new element to the heap and adjust as needed. def insert(self,item): pass # This could be tricky. I am giving it to you. def bubbleup(self, n): if heap.parent(n) == -1: return if self.data[heap.parent(n)] > self.data[n]: self.data[n],self.data[heap.parent(n)] = self.data[heap.parent(n)],self.data[n] self.bubbleup(heap.parent(n)) # Remove the smallest element and adjust the heap. def extractmin(self): pass # This could be tricky. I am giving it to you. def bubbleDown(self,p): c = self.child(p) min_index = p for i in [0, 1]: if ((c + i) <= self.count): if self.data[min_index] > self.data[c + i]: min_index = c+i if min_index != p: self.data[p], self.data[min_index] = self.data[min_index], self.data[p] self.bubbleDown(min_index) @staticmethod def parent(n): if (n == 1): return (-1) else: return int(n/2) @staticmethod def child(n): return (2 * n) ## Define the iterator for heap. Used in for or list comprehension. def __iter__(self): pass ## overload equality operator def __eq__(self, other): pass # copy constructor - clone the current instance def copy(self): pass ''' hh = heap(10) hh.insert(12) hh.insert(4) hh.insert(8) ''' # ******************************************************** # ** problem 8 ** (10 points) # Write a function that takes in a list of positive integers of # size n and returns a sorted list containing the n/2 smallest elements # use a heap def smallest(lst = [4,2,5,6,8,11,99,6,77]): pass # ******************************************************** # ******************************************************** ### test function from google python course ### ======================================= # Provided simple test() function used in main() to print # what each function returns vs. what it's supposed to return. def test(got, expected): if (hasattr(expected, '__call__')): OK = expected(got) else: OK = (got == expected) if OK: prefix = ' OK ' else: prefix = ' X ' print ('%s got: %s expected: %s' % (prefix, repr(got), repr(expected))) # Provided main() calls the above functions with interesting inputs, # using test() to check if each result is correct or not. def main(): print ('hours') print('# is it greater than 0?') test(hours(), lambda x: x > 0) print ('stack') s = stack() s.push(1) s.push(2) s.push(3) s.push(4) test(s,stack([1, 2, 3, 4])) test(s == s.copy(), True) test([x for x in s], [4,3,2,1]) test(s.peek(),4) test(3 in s, True) test(5 in s, False) test(s.pop(),4) test(s.pop(),3) test(s.peek(),2) test(revstr('abcdef'), 'fedcba') test(revstr(''), '') print ('balanced') test(balanced('dkdk'),True) test(balanced('()()()()'),True) test(balanced('()()()())'),False) test(balanced('()()()()(('),False) test(balanced('(a)s(d)f(g)gh(h)j(k'),False) print ('queue') d = queue() d.enqueue(9) d.enqueue(1) d.enqueue(2) test(d == d.copy(), True) test(d.peek(),9) test(d.data,[9, 1, 2]) test([x for x in d], [9,1,2]) test(2 in d, True) test(5 in d, False) test(d.dequeue(),9) test(d.dequeue(),1) test(d.dequeue(),2) test(2 in d, False) test(d.dequeue(),'queue is empty') print ('\nqueue 2 stacks') d2 = queue2() d2.enqueue(9) d2.enqueue(1) d2.enqueue(2) test(d2 == d2.copy(), True) test(d2 == queue2([9,1,2], []),True) test(d2 == queue2([1,2], []),False) test(d2.peek(),9) test([x for x in d2], [9,1,2]) test(2 in d2, True) test(5 in d2, False) test(d2.dequeue(),9) test(d2.dequeue(),1) test(d2.dequeue(),2) test(2 in d2, False) test(d2.dequeue(),'queue is empty') print ('\nreverseq') q = queue() q.enqueue(1) q.enqueue(2) q.enqueue(3) q.enqueue(4) test(str(reverseq(q)),'queue([4, 3, 2, 1])') q2 = queue2() q2.enqueue(1) q2.enqueue(2) q2.enqueue(3) q2.enqueue(4) test(str(reverseq(q2)),'queue2(stack([4, 3, 2, 1]), stack([]))') print ('\nmyhash') h = myhash(20) h.put("one",1) h.put("two",2) h.put("three",3) h2 = myhash(20) test(h == h.copy(), True) h2.put("one",1) h2.put("two",2) h2.put("three",3) test(h == h2, True) h2.put("four",4) test(h == h2, False) test("one" in h, True) test("zero" in h, False) test([x for x in h],['one', 'three', 'two']) test(h.hashfun("one"),7) test(h.hashfun("two"),19) test(h.hashfun("three"),17) test(h.get("three"),3) test(h.get("four"),False) test(h.remove("three"),None) test(h.get("three"),False) test(h.hashfun('one',True),'Hash of: one = 193501607 ==> 7') test(h.hashfun('two',True),'Hash of: two = 193507359 ==> 19') print ('\nremovedups') test(removedups('abcabcabc'),'abc') test(removedups('abcabcabcefg'), 'abcefg') print ('\nheap') hh = heap(10) hh.insert(12) hh.insert(4) hh.insert(8) test(hh == hh.copy(), True) hh2 = heap(10) hh2.insert(12) hh2.insert(4) hh2.insert(8) test(hh == hh2, True) hh2.insert(80) test(hh == hh2, False) test(str(hh),'heap( [0, 4, 12, 8, 0, 0, 0, 0, 0, 0, 0] )') test(4 in hh, True) test(44 in hh, False) test(0 in hh, False) test([x for x in hh], [4,12,8]) test(hh.child(1),2) test(hh.child(2),4) test(hh.parent(3),1) test(hh.extractmin(),4) test(hh.extractmin(),8) print ('\nsmallest') test(smallest(),[2, 4, 5, 6]) test(smallest([]),[]) test(smallest([1]),[]) test(smallest([1,2]),[1]) test(smallest([3,4,5,6,2,3,4,5,6,7,88,22,11,33,22,44]),[2, 3, 3, 4, 4, 5, 5, 6]) if __name__ == '__main__': main()