def infix_to_prefix(infix): """Converts given infix expression to postfix expression using Shunting Yard Algorithm and converts that postfix to prefix""" if infix == "": return "" #stack to temporarily store operators and paranthesis stack = MyStack(size=len(infix) + 1) postfix = [] # a list to store postifix expression for char in infix: if is_operand(char): postfix.append(char) elif char not in ['(', ')']: while not stack.is_empty() and precedence(char) <= precedence( stack.top()): #Add elements from stack until stack is not empty and precedence of \n #char is less than the top most stack element postfix.append(stack.pop()) stack.push(char) elif char == "(": stack.push(char) elif char == ")": while not stack.is_empty() and stack.top() != "(": postfix.append(stack.pop()) if stack.top() != "(": raise ValueError("Parathesis Mismatch!") stack.pop() while not stack.is_empty(): # pop out and add all existing elements from stack and add in onto postfix postfix.append(stack.pop()) stack.clear_stack() # returns prefix string after converting the postfix passed to convert_to_prefix return convert_to_prefix(postfix)
class MyQueue(object): def __init__(self, capacity): self.output_stack = MyStack(capacity) self.help_stack = MyStack(capacity) self.capacity = capacity self.current_capacity = capacity def __str__(self): output = "Queue: " + str(self.output_stack) + "\n" output += "Helper: " + str(self.help_stack) return output def add(self, value): if self.current_capacity > 0: if self.output_stack.is_empty() == True: self.output_stack.push(value) else: while self.output_stack.is_empty() == False: self.help_stack.push(self.output_stack.pop()) self.output_stack.push(value) self.current_capacity -= 1 while self.help_stack.is_empty() == False: self.output_stack.push(self.help_stack.pop()) else: raise QueueOverFlow def remove(self): try: return self.output_stack.pop() except: raise EmptyQueueExeption
class SetOfStacks(object): def __init__(self, capacity_per_stack): self.capacity_per_stack = capacity_per_stack self.stack = MyStack(100) self.stack.push(MyStack(capacity_per_stack)) def __str__(self): return str(self.stack) def push(self, value): top = self.stack.peek() if top.get_current_capacity() > 1: top.push(value) else: self.stack.push(MyStack(self.capacity_per_stack)) self.stack.peek().push(value) def pop(self): top = self.stack.peek() val = top.pop() if top.get_current_capacity() > self.capacity_per_stack - 1: self.stack.pop() return val
class NewQueue: def __init__(self): self.main_stack = MyStack() # Write your code here # Inserts Element in the Queue def enqueue(self, value): self.main_stack.push(value) return True # Removes Element From Queue def dequeue(self): # Write your code here temp_stack = MyStack() while not self.main_stack.size() == 1: temp_stack.push(self.main_stack.pop()) popped_item = self.main_stack.pop() while not temp_stack.is_empty(): self.main_stack.push(temp_stack.pop()) return popped_item def __str__(self): return str(self.main_stack)
class MinStack(MyStack): def __init__(self): super(MinStack, self).__init__() self.local_mins = MyStack() def push(self, data: int): super(MinStack, self).push(data) if self.local_mins.top is None: self.local_mins.push(data) elif self.local_mins.top.data > data: self.local_mins.push(data) def pop(self): node: StackNode = super(MinStack, self).pop() data: int = node.data if data == self.local_mins.top.data: self.local_mins.pop() return node def min(self): return self.local_mins.top.data
def dequeue(self): # Write your code here temp_stack = MyStack() while not self.main_stack.size() == 1: temp_stack.push(self.main_stack.pop()) popped_item = self.main_stack.pop() while not temp_stack.is_empty(): self.main_stack.push(temp_stack.pop()) return popped_item
def infix_to_postfix(infix): """Converts given infix expression to postfix expression using Shunting Yard Algorithm""" #stack to temporarily store operators and paranthesis stack = MyStack(size= len(infix)+1) postfix = [] # a list to store postifix expression # Returns True if char is an operand is_operand = lambda char: char.isalpha() or char.isnumeric() # Returns the precedence of char from PRIORITY dict""" PRIORITY = {"+": 1, "-": 1, "*": 2, "/": 2, "%": 2, "^": 3} precedence = lambda char: PRIORITY[char] if char in PRIORITY else -1 for char in infix: if is_operand(char): postfix.append(char) elif char not in ['(',')']: while not stack.is_empty() and precedence(char) <= precedence(stack.top()): #Add elements from stack until stack is not empty and precedence of \n #char is less than the top most stack element postfix.append(stack.pop()) stack.push(char) elif char == "(": stack.push(char) elif char == ")": while not stack.is_empty() and stack.top() != "(": postfix.append(stack.pop()) if stack.top() != "(": raise ValueError("Parathesis Mismatch!") stack.pop() while not stack.is_empty(): # pop out and add all existing elements from stack and add in onto postfix postfix.append(stack.pop()) return " ".join(postfix)
def pop(self) -> StackNode: ''' pops an item off of the top of the stack''' if not self.top: return -1 self.size -= 1 return MyStack.pop(self)
class BTree: ''' This module implements the BTree class -- a tree of BTreeNodes. Items can be inserted and deleted from the tree. Each node must have at least degree items in it (except for the root node) ''' def __init__(self, degree): # This method is complete. self.degree = degree self.rootNode = BTreeNode(degree) # If time, file creation code, etc. self.nodes = {} self.stackOfNodes = MyStack() self.rootNode.setIndex(1) self.writeAt(1, self.rootNode) self.rootIndex = 1 self.freeIndex = 2 def __str__(self): # This method is complete. st = ' The degree of the BTree is ' + str(self.degree)+\ '.\n' st += ' The index of the root node is ' + \ str(self.rootIndex) + '.\n' for x in range(1, self.freeIndex): node = self.readFrom(x) if node.getNumberOfKeys() > 0: st += str(node) return st def delete(self, anItem): ''' Answer None if a matching item is not found. If found, answer the entire item. ''' searchResult = self.searchTree(anItem) n = self.degree if searchResult['found']: #the item is in the tree; delete it aNode = self.readFrom( searchResult['fileIndex']) #get the node that contains anItem nodeIndex = searchResult['nodeIndex'] done = False if not aNode.isLeaf( ): #if anItem is in a leaf node, find the inorder successor (ioSuc, iosNode) = self.inorderSuccessor(aNode, nodeIndex) searchResult = self.searchTree( ioSuc ) #search the tree in order to get the stack of nodes on the search path aNode.getItems( )[nodeIndex] = ioSuc #replace anItem with the inorder successor iosNode.removeItem( 0) #remove the inorder successor from its original node self.writeAt(aNode.getIndex(), aNode) #write the revised aNode to the file aNode = iosNode #reset what aNode refers to anItem = ioSuc else: #if anItem was already in a leaf node aNode.removeItem(nodeIndex) #remove anItem from the leaf node while not done and aNode.getNumberOfKeys() < n and aNode.getIndex( ) != self.rootIndex: #while aNode has less than n keys and is not the root parentNode = self.stackOfNodes.pop() #get the parent node (parentIndex, siblingNode, sibSide) = self.findParentAndSibling( anItem, parentNode) #get the parent index and the sibling totNumKeys = siblingNode.getNumberOfKeys( ) + aNode.getNumberOfKeys( ) + 1 #find the total number of keys, including the parent item tempNode = BTreeNode(2 * n) #create a temporary BTreeNode if sibSide == "right": #if using the right sibling, copy aNode, then parent, then sibling tempNode.copyItemsAndChildren(aNode, 0, aNode.getNumberOfKeys() - 1, 0) tempNode.getItems()[aNode.getNumberOfKeys( )] = parentNode.getItems()[parentIndex] tempNode.copyItemsAndChildren( siblingNode, 0, siblingNode.getNumberOfKeys() - 1, aNode.getNumberOfKeys() + 1) else: #if using the left sibling, copy the sibling, then parent, then aNode tempNode.copyItemsAndChildren( siblingNode, 0, siblingNode.getNumberOfKeys() - 1, 0) tempNode.getItems()[siblingNode.getNumberOfKeys( )] = parentNode.getItems()[parentIndex] tempNode.copyItemsAndChildren( aNode, 0, aNode.getNumberOfKeys() - 1, siblingNode.getNumberOfKeys() + 1) aNode.clear() #clear the items and children from the two nodes siblingNode.clear() if totNumKeys > 2 * n: #case 2a: redistribute sepKey = (totNumKeys + 1) // 2 #find the new separating key aNode.copyItemsAndChildren( tempNode, 0, sepKey - 2, 0 ) #put the items of the temp node back to where they belong, redistributed parentNode.getItems()[parentIndex] = tempNode.getItems()[ sepKey - 1] siblingNode.copyItemsAndChildren(tempNode, sepKey, totNumKeys - 1, 0) aNode.setNumberOfKeys(sepKey - 1) siblingNode.setNumberOfKeys(totNumKeys - sepKey) else: #case 2b: merge parentNode.removeItem( parentIndex ) #remove the parent item from the parent node if sibSide == "right": #remove the child representing the right sibling parentNode.removeChild(parentIndex + 1) if parentNode.getNumberOfKeys( ) == 0: #if the parent is now empty after the merge, make aNode the root of the tree done = True self.rootNode = aNode self.rootIndex = aNode.getIndex() aNode.copyItemsAndChildren( tempNode, 0, totNumKeys - 1, 0) #merge all the items into aNode aNode.setNumberOfKeys(totNumKeys) else: #remove the child representing the right sibling (aNode) parentNode.removeChild(parentIndex + 1) if parentNode.getNumberOfKeys( ) == 0: #if the parent is now empty after the merge, make sibNode the root of the tree done = True self.rootNode = siblingNode self.rootIndex = siblingNode.getIndex() siblingNode.copyItemsAndChildren( tempNode, 0, totNumKeys - 1, 0) #merge all the items into the sibling node siblingNode.setNumberOfKeys(totNumKeys) self.writeAt(aNode.getIndex(), aNode) #write the updates to the file self.writeAt(siblingNode.getIndex(), siblingNode) self.writeAt(parentNode.getIndex(), parentNode) aNode = parentNode #move up the tree and check if it's ok else: #the item is not in the tree; return None return None def inorderSuccessor(self, node, nodeIndex): '''This method finds the inorder successor given the node containing the original item and the node index of the original item. It returns a tuple containing the inorder successor along with the node containing the inorder successor ''' fIndex = node.getChild()[nodeIndex + 1] #get the right child of the item aNode = self.readFrom(fIndex) #get the corresponding node while not aNode.isLeaf(): #while it's not a leaf node fIndex = aNode.getChild()[0] #get the index of the left-most child aNode = self.readFrom(fIndex) #get the corresponding node inorderSuccessor = aNode.getItems()[0] #get the inorder successor return (inorderSuccessor, aNode) def findParentAndSibling(self, anItem, parentNode): '''This method finds the parent index and the sibling node given the item and the parent node. It returns the right child (if it exists), otherwise the left child. ''' currentIndex = 0 found = False parentItems = parentNode.getItems() parentChild = parentNode.getChild() while not found: #find the index of the parent and the sibling if currentIndex == parentNode.getNumberOfKeys( ): #we found the parent and we have a left sibling parentIndex = currentIndex - 1 siblingIndex = parentChild[currentIndex - 1] sibSide = "left" found = True elif parentItems[ currentIndex] > anItem: #we found the parent and we have a right sibling parentIndex = currentIndex siblingIndex = parentChild[currentIndex + 1] sibSide = "right" found = True else: #if haven't found parent yet, increment the currentIndex currentIndex += 1 sibling = self.readFrom(siblingIndex) #get the sibling node return (parentIndex, sibling, sibSide) def inorderOn(self, aFile): ''' Print the items of the BTree in inorder on the file aFile. aFile is open for writing. This method is complete at this time. ''' aFile.write("An inorder traversal of the BTree:\n") self.inorderOnFrom(aFile, self.rootIndex) def inorderOnFrom(self, aFile, index): ''' Print the items of the subtree of the BTree, which is rooted at index, in inorder on aFile. ''' node = self.readFrom(index) #get the node corresponding to the index for i in range(node.getNumberOfKeys()): #for each item in the node left = node.getChild()[i] #get the index of the left child if left != None: #visit the left self.inorderOnFrom(aFile, left) aFile.write(str(node.getItems()[i]) + "\n") #visit the middle right = node.getChild()[ node.getNumberOfKeys()] #get the index of the right child if right != None: #visit the rightmost child self.inorderOnFrom(aFile, right) def insert(self, anItem): ''' Answer None if the BTree already contains a matching item. If not, insert a deep copy of anItem and answer anItem. ''' searchResult = self.searchTree(anItem) #search for anItem if searchResult[ 'found']: #if anItem already exists in the tree, return None return None else: #if anItem doesn't exist in the tree insertNode = self.readFrom(searchResult['fileIndex'] ) #get the node anItem should belong in if insertNode.isFull( ): #if the node is full, need to split the node toParent = deepcopy( anItem) #make a deepcopy of the item we want to insert leftChild = None #since inserting into a leaf node, left and right children are None rightChild = None while insertNode.isFull(): splitNode = insertNode.addItemAndSplit( toParent, leftChild, rightChild) #split the full node splitNode.setIndex( self.freeIndex ) #set the index of the new node to be the next available index self.freeIndex += 1 #increment the free index number toParent = deepcopy(insertNode.getItems()[ insertNode.getNumberOfKeys() - 1]) #get the item that will go to the parent node insertNode.getItems()[ insertNode.getNumberOfKeys() - 1] = None #get rid of the record of the parent item insertNode.getChild()[insertNode.getNumberOfKeys( )] = None #get rid of the right child of the parent in the insertNode insertNode.setNumberOfKeys(insertNode.getNumberOfKeys() - 1) leftChild = insertNode.getIndex( ) #get the left and right indices of the parent rightChild = splitNode.getIndex() self.writeAt(leftChild, insertNode) #write both nodes to the file self.writeAt(rightChild, splitNode) insertNode = self.stackOfNodes.pop() #get the parent node if insertNode == None: #if there is no parent, create a new root node insertNode = BTreeNode(self.degree) #create a new node insertNode.setIndex( self.freeIndex ) #set the index of the new root node self.rootNode = insertNode self.rootIndex = self.freeIndex #set the root index self.freeIndex += 1 #increment the free index number insertNode.insertItem( toParent, leftChild, rightChild ) #if the parent node isn't full, just insert the item self.writeAt(insertNode.getIndex(), insertNode) #write the final node to the file else: #there is room for anItem, so just perform an insert insertNode.insertItem(deepcopy(anItem)) self.writeAt(searchResult['fileIndex'], insertNode) #write the node to the file return anItem #return the item def levelByLevel(self, aFile): ''' Print the nodes of the BTree level-by-level on aFile. ''' aFile.write("A level-by-level listing of the nodes:\n") aQueue = Queue() #create an empty queue aQueue.enqueue(self.rootNode) #enqueue the root node while not aQueue.isEmpty(): aNode = aQueue.dequeue() #get the next node in the queue aFile.write(str(aNode)) #write the node to the file for i in range(aNode.getNumberOfKeys() + 1): #for each of the items in the node child = self.readFrom(aNode.getChild()[i]) #get the child node if child != None: #if there is a child node, enqueue it aQueue.enqueue(child) def readFrom(self, index): ''' Answer the node at entry index of the btree structure. Later adapt to files. This method is complete at this time. ''' if self.nodes.__contains__(index): return self.nodes[index] else: return None def recycle(self, aNode): # For now, do nothing # This method is complete at this time. aNode.clear() def retrieve(self, anItem): ''' If found, answer a deep copy of the matching item. If not found, answer None ''' searchResult = self.searchTree(anItem) if searchResult['found']: #if anItem is in the tree node = self.readFrom( searchResult['fileIndex']) #get the node that anItem is in return deepcopy(node.getItems()[ searchResult['nodeIndex']]) #return a deepcopy of anItem else: return None def searchTree(self, anItem): ''' Answer a dictionary. If there is a matching item, at 'found' is True, at 'fileIndex' is the index of the node in the BTree with the matching item, and at 'nodeIndex' is the index into the node of the matching item. If not, at 'found' is False, but the entry for 'fileIndex' is the leaf node where the search terminated. An important function of this method is that it pushes all of the nodes of the search path from the rootnode, down to, but not including the corresponding leaf node of a search (or the node containing a match). Again, the rootnode is pushed if it is not a leaf node and has no match. ''' self.stackOfNodes.clear() #clear the existing stack currentNode = self.readFrom(self.rootIndex) #get the root node searchResult = currentNode.searchNode( anItem) #search the root node for anItem while not searchResult['found'] and not currentNode.isLeaf( ): #while we haven't found anItem and the current node we're looking at isn't a leaf node self.stackOfNodes.push( currentNode) #push the current node onto the stack nextNodeIndex = currentNode.getChild()[searchResult[ 'nodeIndex']] #get the next index on the search path currentNode = self.readFrom( nextNodeIndex) #get the node associated with the next index searchResult = currentNode.searchNode( anItem) #search that node for anItem searchResult['fileIndex'] = currentNode.getIndex( ) #set the file index to be the index of the last node searched return searchResult def update(self, anItem): ''' If found, update the item with a matching key to be a deep copy of anItem and answer anItem. If not, answer None. ''' searchResult = self.searchTree(anItem) #search for anItem if searchResult['found']: #if anItem is in the tree fileIndex = searchResult['fileIndex'] nodeIndex = searchResult['nodeIndex'] uNode = self.readFrom(fileIndex) #get the node that anItem is in if uNode != None: uNode.getItems()[nodeIndex] = deepcopy( anItem) #update the node with anItem return anItem else: return None else: return None def writeAt(self, index, aNode): ''' Set the element in the btree with the given index to aNode. This method must be invoked to make any permanent changes to the btree. We may later change this method to work with files. This method is complete at this time. ''' self.nodes[index] = aNode
class BTree: ''' This module implements the BTree class -- a tree of BTreeNodes. Items can be inserted and deleted from the tree. Each node must have at least degree items in it (except for the root node) ''' def __init__(self, degree): # This method is complete. self.degree = degree self.rootNode = BTreeNode(degree) # If time, file creation code, etc. self.nodes = {} self.stackOfNodes = MyStack() self.rootNode.setIndex(1) self.writeAt(1, self.rootNode) self.rootIndex = 1 self.freeIndex = 2 def __str__(self): # This method is complete. st = ' The degree of the BTree is ' + str(self.degree)+\ '.\n' st += ' The index of the root node is ' + \ str(self.rootIndex) + '.\n' for x in range(1, self.freeIndex): node = self.readFrom(x) if node.getNumberOfKeys() > 0: st += str(node) return st def delete(self, anItem): ''' Answer None if a matching item is not found. If found, answer the entire item. ''' searchResult = self.searchTree(anItem) n = self.degree if searchResult['found']: #the item is in the tree; delete it aNode = self.readFrom(searchResult['fileIndex']) #get the node that contains anItem nodeIndex = searchResult['nodeIndex'] done = False if not aNode.isLeaf(): #if anItem is in a leaf node, find the inorder successor (ioSuc, iosNode) = self.inorderSuccessor(aNode, nodeIndex) searchResult = self.searchTree(ioSuc) #search the tree in order to get the stack of nodes on the search path aNode.getItems()[nodeIndex] = ioSuc #replace anItem with the inorder successor iosNode.removeItem(0) #remove the inorder successor from its original node self.writeAt(aNode.getIndex(), aNode) #write the revised aNode to the file aNode = iosNode #reset what aNode refers to anItem = ioSuc else: #if anItem was already in a leaf node aNode.removeItem(nodeIndex) #remove anItem from the leaf node while not done and aNode.getNumberOfKeys() < n and aNode.getIndex() != self.rootIndex: #while aNode has less than n keys and is not the root parentNode = self.stackOfNodes.pop() #get the parent node (parentIndex, siblingNode, sibSide) = self.findParentAndSibling(anItem, parentNode) #get the parent index and the sibling totNumKeys = siblingNode.getNumberOfKeys() + aNode.getNumberOfKeys() + 1 #find the total number of keys, including the parent item tempNode = BTreeNode(2*n) #create a temporary BTreeNode if sibSide == "right": #if using the right sibling, copy aNode, then parent, then sibling tempNode.copyItemsAndChildren(aNode, 0, aNode.getNumberOfKeys()-1, 0) tempNode.getItems()[aNode.getNumberOfKeys()] = parentNode.getItems()[parentIndex] tempNode.copyItemsAndChildren(siblingNode, 0, siblingNode.getNumberOfKeys()-1, aNode.getNumberOfKeys()+1) else: #if using the left sibling, copy the sibling, then parent, then aNode tempNode.copyItemsAndChildren(siblingNode, 0, siblingNode.getNumberOfKeys()-1, 0) tempNode.getItems()[siblingNode.getNumberOfKeys()] = parentNode.getItems()[parentIndex] tempNode.copyItemsAndChildren(aNode, 0, aNode.getNumberOfKeys()-1, siblingNode.getNumberOfKeys()+1) aNode.clear() #clear the items and children from the two nodes siblingNode.clear() if totNumKeys > 2*n: #case 2a: redistribute sepKey = (totNumKeys + 1)//2 #find the new separating key aNode.copyItemsAndChildren(tempNode, 0, sepKey-2, 0) #put the items of the temp node back to where they belong, redistributed parentNode.getItems()[parentIndex] = tempNode.getItems()[sepKey-1] siblingNode.copyItemsAndChildren(tempNode, sepKey, totNumKeys-1, 0) aNode.setNumberOfKeys(sepKey-1) siblingNode.setNumberOfKeys(totNumKeys-sepKey) else: #case 2b: merge parentNode.removeItem(parentIndex) #remove the parent item from the parent node if sibSide == "right": #remove the child representing the right sibling parentNode.removeChild(parentIndex+1) if parentNode.getNumberOfKeys() == 0: #if the parent is now empty after the merge, make aNode the root of the tree done = True self.rootNode = aNode self.rootIndex = aNode.getIndex() aNode.copyItemsAndChildren(tempNode, 0, totNumKeys-1, 0) #merge all the items into aNode aNode.setNumberOfKeys(totNumKeys) else: #remove the child representing the right sibling (aNode) parentNode.removeChild(parentIndex+1) if parentNode.getNumberOfKeys() == 0: #if the parent is now empty after the merge, make sibNode the root of the tree done = True self.rootNode = siblingNode self.rootIndex = siblingNode.getIndex() siblingNode.copyItemsAndChildren(tempNode, 0, totNumKeys-1, 0) #merge all the items into the sibling node siblingNode.setNumberOfKeys(totNumKeys) self.writeAt(aNode.getIndex(), aNode) #write the updates to the file self.writeAt(siblingNode.getIndex(), siblingNode) self.writeAt(parentNode.getIndex(), parentNode) aNode = parentNode #move up the tree and check if it's ok else: #the item is not in the tree; return None return None def inorderSuccessor(self, node, nodeIndex): '''This method finds the inorder successor given the node containing the original item and the node index of the original item. It returns a tuple containing the inorder successor along with the node containing the inorder successor ''' fIndex = node.getChild()[nodeIndex+1] #get the right child of the item aNode = self.readFrom(fIndex) #get the corresponding node while not aNode.isLeaf(): #while it's not a leaf node fIndex = aNode.getChild()[0] #get the index of the left-most child aNode = self.readFrom(fIndex) #get the corresponding node inorderSuccessor = aNode.getItems()[0] #get the inorder successor return (inorderSuccessor, aNode) def findParentAndSibling(self, anItem, parentNode): '''This method finds the parent index and the sibling node given the item and the parent node. It returns the right child (if it exists), otherwise the left child. ''' currentIndex = 0 found = False parentItems = parentNode.getItems() parentChild = parentNode.getChild() while not found: #find the index of the parent and the sibling if currentIndex == parentNode.getNumberOfKeys(): #we found the parent and we have a left sibling parentIndex = currentIndex - 1 siblingIndex = parentChild[currentIndex-1] sibSide = "left" found = True elif parentItems[currentIndex] > anItem: #we found the parent and we have a right sibling parentIndex = currentIndex siblingIndex = parentChild[currentIndex+1] sibSide = "right" found = True else: #if haven't found parent yet, increment the currentIndex currentIndex += 1 sibling = self.readFrom(siblingIndex) #get the sibling node return (parentIndex, sibling, sibSide) def inorderOn(self, aFile): ''' Print the items of the BTree in inorder on the file aFile. aFile is open for writing. This method is complete at this time. ''' aFile.write("An inorder traversal of the BTree:\n") self.inorderOnFrom( aFile, self.rootIndex) def inorderOnFrom(self, aFile, index): ''' Print the items of the subtree of the BTree, which is rooted at index, in inorder on aFile. ''' node = self.readFrom(index) #get the node corresponding to the index for i in range(node.getNumberOfKeys()): #for each item in the node left = node.getChild()[i] #get the index of the left child if left != None: #visit the left self.inorderOnFrom(aFile, left) aFile.write(str(node.getItems()[i])+"\n") #visit the middle right = node.getChild()[node.getNumberOfKeys()]#get the index of the right child if right != None: #visit the rightmost child self.inorderOnFrom(aFile, right) def insert(self, anItem): ''' Answer None if the BTree already contains a matching item. If not, insert a deep copy of anItem and answer anItem. ''' searchResult = self.searchTree(anItem) #search for anItem if searchResult['found']: #if anItem already exists in the tree, return None return None else: #if anItem doesn't exist in the tree insertNode = self.readFrom(searchResult['fileIndex']) #get the node anItem should belong in if insertNode.isFull(): #if the node is full, need to split the node toParent = deepcopy(anItem) #make a deepcopy of the item we want to insert leftChild = None #since inserting into a leaf node, left and right children are None rightChild = None while insertNode.isFull(): splitNode = insertNode.addItemAndSplit(toParent, leftChild, rightChild) #split the full node splitNode.setIndex(self.freeIndex) #set the index of the new node to be the next available index self.freeIndex += 1 #increment the free index number toParent = deepcopy(insertNode.getItems()[insertNode.getNumberOfKeys()-1]) #get the item that will go to the parent node insertNode.getItems()[insertNode.getNumberOfKeys()-1] = None #get rid of the record of the parent item insertNode.getChild()[insertNode.getNumberOfKeys()] = None #get rid of the right child of the parent in the insertNode insertNode.setNumberOfKeys(insertNode.getNumberOfKeys()-1) leftChild = insertNode.getIndex() #get the left and right indices of the parent rightChild = splitNode.getIndex() self.writeAt(leftChild, insertNode) #write both nodes to the file self.writeAt(rightChild, splitNode) insertNode = self.stackOfNodes.pop() #get the parent node if insertNode == None: #if there is no parent, create a new root node insertNode = BTreeNode(self.degree) #create a new node insertNode.setIndex(self.freeIndex) #set the index of the new root node self.rootNode = insertNode self.rootIndex = self.freeIndex #set the root index self.freeIndex += 1 #increment the free index number insertNode.insertItem(toParent, leftChild, rightChild)#if the parent node isn't full, just insert the item self.writeAt(insertNode.getIndex(), insertNode) #write the final node to the file else: #there is room for anItem, so just perform an insert insertNode.insertItem(deepcopy(anItem)) self.writeAt(searchResult['fileIndex'], insertNode) #write the node to the file return anItem #return the item def levelByLevel(self, aFile): ''' Print the nodes of the BTree level-by-level on aFile. ''' aFile.write("A level-by-level listing of the nodes:\n") aQueue = Queue() #create an empty queue aQueue.enqueue(self.rootNode) #enqueue the root node while not aQueue.isEmpty(): aNode = aQueue.dequeue() #get the next node in the queue aFile.write(str(aNode)) #write the node to the file for i in range(aNode.getNumberOfKeys()+1): #for each of the items in the node child = self.readFrom(aNode.getChild()[i]) #get the child node if child != None: #if there is a child node, enqueue it aQueue.enqueue(child) def readFrom(self, index): ''' Answer the node at entry index of the btree structure. Later adapt to files. This method is complete at this time. ''' if self.nodes.__contains__(index): return self.nodes[index] else: return None def recycle(self, aNode): # For now, do nothing # This method is complete at this time. aNode.clear() def retrieve(self, anItem): ''' If found, answer a deep copy of the matching item. If not found, answer None ''' searchResult = self.searchTree(anItem) if searchResult['found']: #if anItem is in the tree node = self.readFrom(searchResult['fileIndex']) #get the node that anItem is in return deepcopy(node.getItems()[searchResult['nodeIndex']]) #return a deepcopy of anItem else: return None def searchTree(self, anItem): ''' Answer a dictionary. If there is a matching item, at 'found' is True, at 'fileIndex' is the index of the node in the BTree with the matching item, and at 'nodeIndex' is the index into the node of the matching item. If not, at 'found' is False, but the entry for 'fileIndex' is the leaf node where the search terminated. An important function of this method is that it pushes all of the nodes of the search path from the rootnode, down to, but not including the corresponding leaf node of a search (or the node containing a match). Again, the rootnode is pushed if it is not a leaf node and has no match. ''' self.stackOfNodes.clear() #clear the existing stack currentNode = self.readFrom(self.rootIndex) #get the root node searchResult = currentNode.searchNode(anItem) #search the root node for anItem while not searchResult['found'] and not currentNode.isLeaf(): #while we haven't found anItem and the current node we're looking at isn't a leaf node self.stackOfNodes.push(currentNode) #push the current node onto the stack nextNodeIndex = currentNode.getChild()[searchResult['nodeIndex']] #get the next index on the search path currentNode = self.readFrom(nextNodeIndex) #get the node associated with the next index searchResult = currentNode.searchNode(anItem) #search that node for anItem searchResult['fileIndex'] = currentNode.getIndex() #set the file index to be the index of the last node searched return searchResult def update(self, anItem): ''' If found, update the item with a matching key to be a deep copy of anItem and answer anItem. If not, answer None. ''' searchResult = self.searchTree(anItem) #search for anItem if searchResult['found']: #if anItem is in the tree fileIndex = searchResult['fileIndex'] nodeIndex = searchResult['nodeIndex'] uNode = self.readFrom(fileIndex) #get the node that anItem is in if uNode != None: uNode.getItems()[nodeIndex] = deepcopy(anItem) #update the node with anItem return anItem else: return None else: return None def writeAt(self, index, aNode): ''' Set the element in the btree with the given index to aNode. This method must be invoked to make any permanent changes to the btree. We may later change this method to work with files. This method is complete at this time. ''' self.nodes[index] = aNode