def traverseDFSpreorder(self):
     #root, left subtree, right subtree
     keys = []
     dfsS = Stack()
     dfsS.push(self.root)
     cur = dfsS.pop()
     while cur:
         #print("cur.key = %s"%cur.key)
         keys.append(cur.key)
         #print("%s added to keys" % str(cur.key))
         if (cur.right):
             dfsS.push(cur.right)
             #print("cur.right.key = %s"%cur.right.key)
         if (cur.left):
             dfsS.push(cur.left)
             #print('cur.left.key = %s' % cur.left.key)
         cur = dfsS.pop()
         #print("--------------------------------")
     return keys
 def traverseDFSpreorder(self):
     #root, left subtree, right subtree
     keys = []
     dfsS = Stack()
     dfsS.push(self.root)
     cur = dfsS.pop()
     while cur:
         #print("cur.key = %s"%cur.key)
         keys.append(cur.key)
         #print("%s added to keys" % str(cur.key))
         if(cur.right):
             dfsS.push(cur.right)
             #print("cur.right.key = %s"%cur.right.key)
         if(cur.left):
             dfsS.push(cur.left)
             #print('cur.left.key = %s' % cur.left.key)
         cur = dfsS.pop()
         #print("--------------------------------")
     return keys
 def traverseDFSpostorder(self):
     #left subtree, right subtree, root
     keys = []
     dfsS = Stack()
     dfsS.push(self.root)
     cur = dfsS.pop()
     while cur:
         #print("cur.key = %s"%cur.key)
         if (((not cur.left) or (cur.left.key in keys))
                 and ((not cur.right) or (cur.right.key in keys))):
             keys.append(cur.key)
             #print("%s added to keys" % str(cur.key))
         else:
             dfsS.push(cur)
             if (cur.right):
                 dfsS.push(cur.right)
                 #print("cur.right.key = %s"%cur.right.key)
             if (cur.left):
                 dfsS.push(cur.left)
                 #print('cur.left.key = %s' % cur.left.key)
         cur = dfsS.pop()
         #print("--------------------------------")
     return keys
 def __init__(self):
     self.root = None
     self.current = None
     self.queue = Queue()
     self.past = Stack()
class BinaryHeap:
    def __init__(self):
        self.root = None
        self.current = None
        self.queue = Queue()
        self.past = Stack()
        
    def __str__(self):
        return self.traverseBFS()
    
    def traverseBFS(self):
        string = ""
        bfsQ = Queue()
        bfsQ.enQueue(self.root)
        cur = bfsQ.deQueue()
        while cur:
            string += ("\n%s - (%s|%s, %s)"%(cur.key,
                                           cur.parent.key if cur.parent else None,
                                           cur.left.key if cur.left else None,
                                           cur.right.key if cur.right else None))
            if(cur.left):
                bfsQ.enQueue(cur.left)
            if(cur.right):
                bfsQ.enQueue(cur.right)
            cur = bfsQ.deQueue()
        if(string == ""):
            string = "(Empty)"
        return string
    
    def insert(self, key):
        if(not self.root):
            self.root = Node(key, None, None, None)
            self.current = self.root
            #print("Stacking %d"%self.current.key)
            self.past.push(self.current)
            return True
        if(self.current.left and self.current.right):
            self.current = self.queue.deQueue()
            #print("DeQ %d"%self.current.key)
            #print("Stacking %d"%self.current.key)
            self.past.push(self.current)
        if(not self.current.left):
            self.current.left = Node(key, self.current,None,None)
            #print("Qing1 %d"%self.current.left.key)
            self.queue.enQueue(self.current.left)
            self.heapifyUp(self.current.left)
            return True
        elif(not self.current.right):
            self.current.right = Node(key, self.current,None,None)
            self.queue.enQueue(self.current.right)
            #print("Qing2 %d"%self.current.right.key)
            self.heapifyUp(self.current.right)
            return True
        return False
    
    def insertList(self, alist):
        boolResult = True
        for item in alist:
            if(self.insert(item) == False):
                boolResult = False
        return boolResult
        
    def heapifyUp(self, node):
        while(node.parent and node.key > node.parent.key):
            temp = node.parent.key
            node.parent.key = node.key
            node.key = temp
            node = node.parent
            
    def delete(self):
        if(not self.root):
            return None
        returnValue = self.root.key
        if(self.current.right):
            self.root.key = self.current.right.key
            self.current.right.parent = None
            self.current.right = None
            returned = self.queue.getLast()
            #print("deQing %s"%returned.key)
        elif(self.current.left):
            if(self.current == self.root):
                self.root.key = self.current.left.key
                self.current.left.parent = None
                self.current.left = None
                returned = self.queue.getLast()
                #print("deQing %s"%returned.key)
            else:
                self.root.key = self.current.left.key
                self.current.left.parent = None
                self.current.left = None
                returned = self.queue.getLast()
                #print("deQing %s"%returned.key)
                pop = self.past.pop()
                #print("Popping and inserting %s"%pop.key)
                self.queue.insert(pop)
                self.current = self.past.pop()
                self.past.push(self.current)
        else:
            pop = self.past.pop()
            #print("Popping%s"%pop.key)
            self.root = None
        self.heapifyDown(self.root)
        return returnValue
    
    def heapifyDown(self, ptr):
        #root is none, or no children to swap
        if(not ptr or (not ptr.left and not ptr.right)):
            return
        if(not ptr.right or ptr.left.key > ptr.right.key):
            if(ptr.left.key > ptr.key):
                temp = ptr.key
                ptr.key = ptr.left.key
                ptr.left.key = temp
                ptr = ptr.left
            else:
                return
        else:
            if(ptr.right.key > ptr.key):
                temp = ptr.key
                ptr.key = ptr.right.key
                ptr.right.key = temp
                ptr = ptr.right
            else:
                return
        self.heapifyDown(ptr)
        
    def merge(self, heap):
        heapData = heap.returnBFS()
        self.insertList(heapData)
    
    def peek(self):
        return self.root.key if self.root else None
        
    def returnBFS(self):
        keys = []
        bfsQ = Queue()
        bfsQ.enQueue(self.root)
        cur = bfsQ.deQueue()
        while cur:
            keys.append(cur.key)
            if(cur.left):
                bfsQ.enQueue(cur.left)
            if(cur.right):
                bfsQ.enQueue(cur.right)
            cur = bfsQ.deQueue()
        return keys
    
    def copyHeap(self):
        copy  = BinaryHeap()
        copy.insertList(self.returnBFS())
        return copy
 def __init__(self):
     self.root = None
     self.current = None
     self.queue = Queue()
     self.past = Stack()
class BinaryHeap:
    def __init__(self):
        self.root = None
        self.current = None
        self.queue = Queue()
        self.past = Stack()

    def __str__(self):
        return self.traverseBFS()

    def traverseBFS(self):
        string = ""
        bfsQ = Queue()
        bfsQ.enQueue(self.root)
        cur = bfsQ.deQueue()
        while cur:
            string += ("\n%s - (%s|%s, %s)" %
                       (cur.key, cur.parent.key if cur.parent else None,
                        cur.left.key if cur.left else None,
                        cur.right.key if cur.right else None))
            if (cur.left):
                bfsQ.enQueue(cur.left)
            if (cur.right):
                bfsQ.enQueue(cur.right)
            cur = bfsQ.deQueue()
        if (string == ""):
            string = "(Empty)"
        return string

    def insert(self, key):
        if (not self.root):
            self.root = Node(key, None, None, None)
            self.current = self.root
            #print("Stacking %d"%self.current.key)
            self.past.push(self.current)
            return True
        if (self.current.left and self.current.right):
            self.current = self.queue.deQueue()
            #print("DeQ %d"%self.current.key)
            #print("Stacking %d"%self.current.key)
            self.past.push(self.current)
        if (not self.current.left):
            self.current.left = Node(key, self.current, None, None)
            #print("Qing1 %d"%self.current.left.key)
            self.queue.enQueue(self.current.left)
            self.heapifyUp(self.current.left)
            return True
        elif (not self.current.right):
            self.current.right = Node(key, self.current, None, None)
            self.queue.enQueue(self.current.right)
            #print("Qing2 %d"%self.current.right.key)
            self.heapifyUp(self.current.right)
            return True
        return False

    def insertList(self, alist):
        boolResult = True
        for item in alist:
            if (self.insert(item) == False):
                boolResult = False
        return boolResult

    def heapifyUp(self, node):
        while (node.parent and node.key > node.parent.key):
            temp = node.parent.key
            node.parent.key = node.key
            node.key = temp
            node = node.parent

    def delete(self):
        if (not self.root):
            return None
        returnValue = self.root.key
        if (self.current.right):
            self.root.key = self.current.right.key
            self.current.right.parent = None
            self.current.right = None
            returned = self.queue.getLast()
            #print("deQing %s"%returned.key)
        elif (self.current.left):
            if (self.current == self.root):
                self.root.key = self.current.left.key
                self.current.left.parent = None
                self.current.left = None
                returned = self.queue.getLast()
                #print("deQing %s"%returned.key)
            else:
                self.root.key = self.current.left.key
                self.current.left.parent = None
                self.current.left = None
                returned = self.queue.getLast()
                #print("deQing %s"%returned.key)
                pop = self.past.pop()
                #print("Popping and inserting %s"%pop.key)
                self.queue.insert(pop)
                self.current = self.past.pop()
                self.past.push(self.current)
        else:
            pop = self.past.pop()
            #print("Popping%s"%pop.key)
            self.root = None
        self.heapifyDown(self.root)
        return returnValue

    def heapifyDown(self, ptr):
        #root is none, or no children to swap
        if (not ptr or (not ptr.left and not ptr.right)):
            return
        if (not ptr.right or ptr.left.key > ptr.right.key):
            if (ptr.left.key > ptr.key):
                temp = ptr.key
                ptr.key = ptr.left.key
                ptr.left.key = temp
                ptr = ptr.left
            else:
                return
        else:
            if (ptr.right.key > ptr.key):
                temp = ptr.key
                ptr.key = ptr.right.key
                ptr.right.key = temp
                ptr = ptr.right
            else:
                return
        self.heapifyDown(ptr)

    def merge(self, heap):
        heapData = heap.returnBFS()
        self.insertList(heapData)

    def peek(self):
        return self.root.key if self.root else None

    def returnBFS(self):
        keys = []
        bfsQ = Queue()
        bfsQ.enQueue(self.root)
        cur = bfsQ.deQueue()
        while cur:
            keys.append(cur.key)
            if (cur.left):
                bfsQ.enQueue(cur.left)
            if (cur.right):
                bfsQ.enQueue(cur.right)
            cur = bfsQ.deQueue()
        return keys

    def copyHeap(self):
        copy = BinaryHeap()
        copy.insertList(self.returnBFS())
        return copy
 def traverseDFSpostorder(self):
     #left subtree, right subtree, root
     keys = []
     dfsS = Stack()
     dfsS.push(self.root)
     cur = dfsS.pop()
     while cur:
         #print("cur.key = %s"%cur.key)
         if(((not cur.left) or (cur.left.key in keys)) and ((not cur.right) or (cur.right.key in keys))):
             keys.append(cur.key)
             #print("%s added to keys" % str(cur.key))
         else:
             dfsS.push(cur)
             if(cur.right):
                 dfsS.push(cur.right)
                 #print("cur.right.key = %s"%cur.right.key)
             if(cur.left):
                 dfsS.push(cur.left)
                 #print('cur.left.key = %s' % cur.left.key)
         cur = dfsS.pop()
         #print("--------------------------------")
     return keys