├── .gitignore ├── ADTs ├── Binary_Heap_Array_Structure.py ├── Binary_Heap_Array_UnitTests.py ├── Priority_Queue.py ├── Queue_head.py ├── Queue_tail.py ├── README.md ├── Stack.py ├── __init__.py └── compare_Queue_Stack.py ├── Graphs ├── ADTs │ ├── Queue_head.py │ ├── Stack.py │ └── __init__.py ├── DAG_Test.py ├── Directed_Cycle_Test.py ├── README.md ├── Undirected_Test.py ├── adjList.py └── adjMatrix.py ├── HashTable ├── HashTable.py ├── HashTable_UnitTests.py ├── Hash_Dist_Tester.py └── README.md ├── LinkedLists ├── LinkedList_Circular.py ├── LinkedList_Circular_UnitTests.py ├── LinkedList_Double.py ├── LinkedList_Double_UnitTests.py ├── LinkedList_Single.py ├── LinkedList_Single_UnitTests.py └── README.md ├── Lorem_ipsum.txt ├── README.md ├── Sorting ├── BubbleSort.py ├── HeapSort.py ├── InsertionSort.py ├── MergeSort.py ├── QuickSort.py ├── README.md ├── SelectionSort.py └── __init__.py ├── Trees ├── ADTs │ ├── Queue_head.py │ ├── Queue_modified_for_heap_use.py │ ├── Stack.py │ └── __init__.py ├── AVL_Tree.py ├── AVL_Tree_UnitTests.py ├── BST_UnitTests_iterative.py ├── BST_UnitTests_recursive.py ├── BST_iterative.py ├── BST_recursive.py ├── Binary_Heap_Tree_Structure.py ├── Binary_Heap_Tree_UnitTests.py ├── README.md ├── RedBlack_Tree.py ├── RedBlack_Tree_UnitTests.py ├── Splay_Tree.py ├── Splay_Tree_UnitTests.py ├── Trie.py ├── Trie_Prefix_Count.py ├── Trie_Prefix_Count_Speed.py ├── Trie_Prefix_Count_Speed_UnitTests.py ├── Trie_Prefix_Count_UnitTests.py ├── Trie_Time_Tester.py ├── Trie_UnitTests.py └── __init__.py └── __init__.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | -------------------------------------------------------------------------------- /ADTs/Binary_Heap_Array_Structure.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/25/2013 4 | 5 | # Binary Heap implemented using an array instead of a binary tree data structure 6 | # Children are at a[2i+1] and a[2i+2] 7 | # Parent is at a[floor((i-1)/2)] 8 | # where the array goes from 0 to n-1 and the root is at index 0 9 | 10 | class BinaryHeap: 11 | def __init__(self): 12 | self.nodes = [] 13 | 14 | def __str__(self): 15 | return self.traverseBFS() 16 | 17 | def traverseBFS(self): 18 | string = "" 19 | index = 0 20 | size = len(self.nodes) 21 | for node in self.nodes: 22 | parent = self.getParent(index) 23 | leftChild = self.getLeftChild(index) 24 | rightChild = self.getRightChild(index) 25 | string += ("\n%s - (%s|%s, %s)"% (node,parent,leftChild,rightChild)) 26 | index += 1 27 | return string if not self.isEmpty() else "(Empty)" 28 | 29 | def returnBFS(self): 30 | return self.nodes 31 | 32 | def insert(self,key): 33 | self.nodes.append(key) 34 | self.heapifyUp() 35 | return True 36 | 37 | def insertList(self, alist): 38 | boolResult = True 39 | for item in alist: 40 | if(self.insert(item) == False): 41 | boolResult = False 42 | return boolResult 43 | 44 | def delete(self): 45 | if self.isEmpty(): 46 | return None 47 | returnValue = self.nodes[0] 48 | self.nodes[0] = self.nodes[-1] 49 | self.nodes.pop() 50 | self.heapifyDown(0, self.getLeftChildIndex(0), self.getRightChildIndex(0)) 51 | return returnValue 52 | 53 | def peek(self): 54 | return self.nodes[0] if not self.isEmpty() else None 55 | 56 | def heapifyUp(self): 57 | child = len(self.nodes)-1 58 | parent = self.getParentIndex(child) 59 | while(self.nodes[child] > self.nodes[parent]): 60 | temp = self.nodes[child] 61 | self.nodes[child] = self.nodes[parent] 62 | self.nodes[parent] = temp 63 | child = parent 64 | parent = self.getParentIndex(child) 65 | 66 | def heapifyDown(self,parent,left,right): 67 | if not self.validChild(left) and not self.validChild(right): 68 | return 69 | if not self.validChild(right) or self.nodes[left] > self.nodes[right]: 70 | if(self.nodes[left] > self.nodes[parent]): 71 | temp = self.nodes[parent] 72 | self.nodes[parent] = self.nodes[left] 73 | self.nodes[left] = temp 74 | parent = self.getLeftChildIndex(parent) 75 | else: 76 | return 77 | else: 78 | if(self.nodes[right] > self.nodes[parent]): 79 | temp = self.nodes[parent] 80 | self.nodes[parent] = self.nodes[right] 81 | self.nodes[right] = temp 82 | parent = self.getRightChildIndex(parent) 83 | else: 84 | return 85 | self.heapifyDown(parent, self.getLeftChildIndex(parent), self.getRightChildIndex(parent)) 86 | 87 | def validChild(self,index): 88 | return True if index < len(self.nodes) else False 89 | 90 | def getLeftChildIndex(self,index): 91 | return ((2*index)+1) 92 | 93 | def getLeftChild(self,index): 94 | child = self.getLeftChildIndex(index) 95 | return self.nodes[child] if self.validChild(child) else None 96 | 97 | def getRightChildIndex(self,index): 98 | return ((2*index)+2) 99 | 100 | def getRightChild(self,index): 101 | child = self.getRightChildIndex(index) 102 | return self.nodes[child] if self.validChild(child) else None 103 | 104 | def getParentIndex(self,index): 105 | return int((index-1)/2) 106 | 107 | def getParent(self,index): 108 | return self.nodes[self.getParentIndex(index)] if index > 0 else None 109 | 110 | def isEmpty(self): 111 | return len(self.nodes)==0 112 | 113 | def copyHeap(self): 114 | copy = BinaryHeap() 115 | copy.insertList(self.returnBFS()) 116 | return copy 117 | 118 | def merge(self, heap): 119 | heapData = heap.returnBFS() 120 | self.insertList(heapData) 121 | 122 | if __name__ == '__main__': 123 | 124 | bh = BinaryHeap() 125 | 126 | for data in range(0,6): 127 | bh.insert(data) 128 | 129 | print(bh) 130 | 131 | print(bh.delete()) 132 | 133 | print(bh) -------------------------------------------------------------------------------- /ADTs/Priority_Queue.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/23/2013 4 | 5 | from Binary_Heap_Array_Structure import BinaryHeap 6 | 7 | class PriorityQueue: 8 | def __init__(self): 9 | self.order = BinaryHeap() 10 | def __str__(self): 11 | temp = self.order.copyHeap() 12 | front = temp.delete() 13 | string = ("") 14 | while front: 15 | string+= (" %s"%front) 16 | front = temp.delete() 17 | string += " " 18 | return string 19 | def enQueue(self,key): 20 | self.order.insert(key) 21 | def deQueue(self): 22 | return self.order.delete() 23 | 24 | if __name__ == '__main__': 25 | pq = PriorityQueue() 26 | 27 | print(pq) 28 | print(pq.deQueue()) 29 | 30 | for data in [1,2,6,4,2,8,9,6,4,3,2,6,7,8,9,10,11,23,53,56,78,98,78,645,23]: 31 | pq.enQueue(data) 32 | 33 | print(pq) 34 | 35 | print("First Item: %s"%pq.deQueue()) 36 | print(pq) 37 | 38 | pq.enQueue(100) 39 | pq.enQueue(53) 40 | pq.enQueue(-1) 41 | 42 | print(pq) -------------------------------------------------------------------------------- /ADTs/Queue_head.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/18/2013 4 | 5 | # Typical Queue. Only has head ptr. New items go to the end. 6 | # Returned values come from the head. 7 | 8 | class Element: 9 | def __init__(self, data, next): 10 | self.data = data 11 | self.next = next 12 | 13 | class Queue: 14 | def __init__(self): 15 | self.head = None 16 | 17 | def __str__(self): 18 | ptr = self.head 19 | if(self.head==None): 20 | string = "Front < > Back" 21 | else: 22 | string = "Front < " 23 | while ptr: 24 | string += ("%s "%ptr.data) 25 | ptr = ptr.next 26 | string += "> Back" 27 | return string 28 | 29 | def enQueue(self,data): 30 | #Append the most recent node to the end 31 | ptr = self.head 32 | if(ptr == None): 33 | self.head = Element(data,self.head) 34 | else: 35 | while ptr.next: 36 | ptr=ptr.next 37 | ptr.next = Element(data, None) 38 | 39 | def deQueue(self): 40 | #move head ptr and return previous head 41 | if(self.head == None): 42 | return None 43 | ptr = self.head 44 | self.head = self.head.next 45 | ptr.next = None 46 | return ptr.data 47 | 48 | if __name__ == '__main__': 49 | myQ = Queue() 50 | 51 | for data in [1,2,3,4,5]: 52 | myQ.enQueue(data) 53 | 54 | print(myQ) 55 | 56 | for key in ['First','Second','Third','Fourth','Fifth']: 57 | print("%s element out: %s" % (key,myQ.deQueue())) 58 | print (myQ) 59 | 60 | print("Test Empty: %s"%myQ.deQueue()) 61 | print (myQ) 62 | 63 | print("_______") 64 | for data in [1,2,3,4]: 65 | print("Adding %s" % data) 66 | myQ.enQueue(data) 67 | print(myQ) 68 | print("Adding %s" % data) 69 | myQ.enQueue(data) 70 | print(myQ) 71 | print("Removing %s"%myQ.deQueue()) 72 | print(myQ) 73 | 74 | print(myQ) 75 | print("_______") 76 | 77 | first = myQ.deQueue() 78 | while first != None: 79 | print("Removing %s"% first) 80 | print(myQ) 81 | first = myQ.deQueue() -------------------------------------------------------------------------------- /ADTs/Queue_tail.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/17/2013 4 | 5 | # Typical Queue. Has a head and tail ptr. New items go to the head. 6 | # Returned values come from the tail. 7 | 8 | class Element: 9 | def __init__(self, data, next, prev): 10 | self.data = data 11 | self.next = next 12 | self.prev = prev 13 | 14 | class Queue: 15 | def __init__(self): 16 | self.head = None 17 | self.tail = None 18 | 19 | def __str__(self): 20 | ptr = self.head 21 | if(self.head==None and self.tail == None): 22 | string = "Last(None) < > First(None)" 23 | else: 24 | string = ("Last(%s) < "% self.head.data) 25 | while ptr != self.tail: 26 | #string += ("(%s-%s-%s), "% (str(ptr.prev.data),str(ptr.data),str(ptr.next.data))) 27 | string += ("(%s), "%ptr.data) 28 | ptr = ptr.next 29 | if(self.tail != None): 30 | string += ("(%s)"%self.tail.data) 31 | #string += ("(%s-%s-%s)"% (str(self.tail.prev.data),str(self.tail.data),str(self.tail.next.data))) 32 | string += (" > First(%s)"% self.tail.data) 33 | return string 34 | 35 | def enQueue(self,data): 36 | if(self.head == None): 37 | self.head = Element(data, self.head, self.tail) 38 | self.tail = self.head 39 | self.head.next = self.tail 40 | self.head.prev = self.tail 41 | self.tail.next = self.head 42 | self.tail.prev = self.head 43 | else: 44 | ptr = self.head 45 | self.head = Element(data, self.head, self.tail) 46 | ptr.prev = self.head 47 | self.tail.next = self.head 48 | 49 | def deQueue(self): 50 | if(self.head == None): 51 | return None 52 | if(self.head == self.tail): 53 | returnData = self.tail.data 54 | self.head = None 55 | self.tail = None 56 | return returnData 57 | ptr = self.tail 58 | returnData = self.tail.data 59 | self.tail = self.tail.prev 60 | ptr.next = None 61 | ptr.prev = None 62 | ptr = None 63 | self.tail.next = self.head 64 | self.head.prev = self.tail 65 | return returnData 66 | 67 | if __name__ == '__main__': 68 | myQ = Queue() 69 | 70 | for data in [1,2,3,4,5]: 71 | myQ.enQueue(data) 72 | 73 | print(myQ) 74 | 75 | for key in ['First','Second','Third','Fourth','Fifth']: 76 | print("%s element out: %s" % (key,myQ.deQueue())) 77 | print (myQ) 78 | 79 | print("Test Empty: %s"%myQ.deQueue()) 80 | print (myQ) 81 | 82 | print("_______") 83 | for data in [1,2,3,4]: 84 | print("Adding %s" % data) 85 | myQ.enQueue(data) 86 | print(myQ) 87 | print("Adding %s" % data) 88 | myQ.enQueue(data) 89 | print(myQ) 90 | print("Removing %s"%myQ.deQueue()) 91 | print(myQ) 92 | 93 | print(myQ) 94 | print("_______") 95 | 96 | first = myQ.deQueue() 97 | while first != None: 98 | print("Removing %s"% first) 99 | print(myQ) 100 | first = myQ.deQueue() -------------------------------------------------------------------------------- /ADTs/README.md: -------------------------------------------------------------------------------- 1 | # *Abstract Data Types (ADTs):* 2 | ## *Types:* 3 | ### Binary Heap (Array Structure) 4 | - Used by Priority Queue 5 | - Unit Tests included (slightly modified from Binary Heap (Tree Structure)) 6 | 7 | ### Priority Queue 8 | - Uses Binary Heap (Array Structure) 9 | 10 | ### Queue 11 | - Linked List, append at end, pop at front (has head ptr ONLY) 12 | - Linked List, insert at beginning, pop at end (has head&tail ptr) 13 | - Used in Iterative Binary Search Tree 14 | - Used in ALL 3 Tries 15 | 16 | - Modified Version - Add ability to insert in front of Queue and remove last item added 17 | - Modified Version - Used in Binary Heap (Tree Structure) 18 | 19 | ### Stack 20 | - Linked List, append at end, pop at front 21 | - Used in Binary Heap (Tree Structure) 22 | - Used in Iterative Binary Search Tree 23 | - Used in ALL 3 Tries 24 | -------------------------------------------------------------------------------- /ADTs/Stack.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/17/2013 4 | 5 | # Typical stack, all operations act on the head/top of the stack. 6 | 7 | class Element: 8 | def __init__(self, data, next): 9 | self.data = data 10 | self.next = next 11 | 12 | class Stack: 13 | def __init__(self): 14 | self.head = None 15 | def __str__(self): 16 | ptr = self.head 17 | string = "TOP\n" 18 | if(self.head): 19 | while ptr: 20 | string += ("%s\n"%ptr.data) 21 | ptr = ptr.next 22 | else: 23 | string += "Empty\n" 24 | return string 25 | 26 | def push(self, element): 27 | self.head = Element(element, self.head) 28 | 29 | 30 | def pop(self): 31 | if self.empty(): return None 32 | result = self.head.data 33 | self.head = self.head.next 34 | return result 35 | 36 | def empty(self): 37 | return self.head == None 38 | 39 | if __name__ == "__main__": 40 | 41 | myS = Stack() 42 | for data in [1,2,3,4,5]: 43 | myS.push(data) 44 | 45 | print(myS) 46 | 47 | for key in ['First','Second','Third','Fourth','Fifth']: 48 | print("%s element out: %s" % (key,myS.pop())) 49 | print (myS) 50 | 51 | print("Test Empty: %s"%myS.pop()) 52 | print (myS) 53 | 54 | print("_______") 55 | for data in [1,2,3,4]: 56 | print("Adding %s" % data) 57 | myS.push(data) 58 | print(myS) 59 | print("Adding %s" % data) 60 | myS.push(data) 61 | print(myS) 62 | print("Removing %s"%myS.pop()) 63 | print(myS) 64 | 65 | print(myS) 66 | print("_______") 67 | 68 | first = myS.pop() 69 | while first != None: 70 | print("Removing %s"% first) 71 | print(myS) 72 | first = myS.pop() 73 | -------------------------------------------------------------------------------- /ADTs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirob2005/Python_Data_Structures/2851dc124e9b52391842521e584bf5ce716f3740/ADTs/__init__.py -------------------------------------------------------------------------------- /ADTs/compare_Queue_Stack.py: -------------------------------------------------------------------------------- 1 | from Queue_head import Queue 2 | from Stack import Stack 3 | 4 | myQ = Queue() 5 | myS = Stack() 6 | 7 | for data in [1,2,3,4,5]: 8 | myQ.enQueue(data) 9 | myS.push(data) 10 | 11 | print("Queue:") 12 | print(myQ) 13 | 14 | print("\nStack: ") 15 | print(myS) 16 | 17 | 18 | print("Removing first element: ") 19 | print("Queue returned: %s"%myQ.deQueue()) 20 | print("Stack returned: %s"%myS.pop()) 21 | 22 | print("\nQueue:") 23 | print(myQ) 24 | 25 | print("\nStack: ") 26 | print(myS) 27 | 28 | print("Adding a 6 element:") 29 | myQ.enQueue(6) 30 | myS.push(6) 31 | print("\nQueue:") 32 | print(myQ) 33 | 34 | print("\nStack: ") 35 | print(myS) 36 | 37 | print("Removing next element: ") 38 | print("Queue returned: %s"%myQ.deQueue()) 39 | print("Stack returned: %s"%myS.pop()) 40 | 41 | print("\nEmptying both...") 42 | queueReturned = myQ.deQueue() 43 | stackReturned = myS.pop() 44 | while queueReturned and stackReturned: 45 | print("Queue Returned: %s"% queueReturned) 46 | print("Stack Returned: %s"% stackReturned) 47 | queueReturned = myQ.deQueue() 48 | stackReturned = myS.pop() 49 | 50 | print("\nFinal: ") 51 | print("Queue:") 52 | print(myQ) 53 | 54 | print("\nStack: ") 55 | print(myS) -------------------------------------------------------------------------------- /Graphs/ADTs/Queue_head.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/18/2013 4 | 5 | # Typical Queue. Only has head ptr. New items go to the end. 6 | # Returned values come from the head. 7 | 8 | class Element: 9 | def __init__(self, data, next): 10 | self.data = data 11 | self.next = next 12 | 13 | class Queue: 14 | def __init__(self): 15 | self.head = None 16 | 17 | def __str__(self): 18 | ptr = self.head 19 | if(self.head==None): 20 | string = "Front < > Back" 21 | else: 22 | string = "Front < " 23 | while ptr: 24 | string += ("%s "%ptr.data) 25 | ptr = ptr.next 26 | string += "> Back" 27 | return string 28 | 29 | def enQueue(self,data): 30 | #Append the most recent node to the end 31 | ptr = self.head 32 | if(ptr == None): 33 | self.head = Element(data,self.head) 34 | else: 35 | while ptr.next: 36 | ptr=ptr.next 37 | ptr.next = Element(data, None) 38 | 39 | def deQueue(self): 40 | #move head ptr and return previous head 41 | if(self.head == None): 42 | return None 43 | ptr = self.head 44 | self.head = self.head.next 45 | ptr.next = None 46 | return ptr.data 47 | 48 | if __name__ == '__main__': 49 | myQ = Queue() 50 | 51 | for data in [1,2,3,4,5]: 52 | myQ.enQueue(data) 53 | 54 | print(myQ) 55 | 56 | for key in ['First','Second','Third','Fourth','Fifth']: 57 | print("%s element out: %s" % (key,myQ.deQueue())) 58 | print (myQ) 59 | 60 | print("Test Empty: %s"%myQ.deQueue()) 61 | print (myQ) 62 | 63 | print("_______") 64 | for data in [1,2,3,4]: 65 | print("Adding %s" % data) 66 | myQ.enQueue(data) 67 | print(myQ) 68 | print("Adding %s" % data) 69 | myQ.enQueue(data) 70 | print(myQ) 71 | print("Removing %s"%myQ.deQueue()) 72 | print(myQ) 73 | 74 | print(myQ) 75 | print("_______") 76 | 77 | first = myQ.deQueue() 78 | while first != None: 79 | print("Removing %s"% first) 80 | print(myQ) 81 | first = myQ.deQueue() -------------------------------------------------------------------------------- /Graphs/ADTs/Stack.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/17/2013 4 | 5 | # Typical stack, all operations act on the head/top of the stack. 6 | 7 | class Element: 8 | def __init__(self, data, next): 9 | self.data = data 10 | self.next = next 11 | 12 | class Stack: 13 | def __init__(self): 14 | self.head = None 15 | def __str__(self): 16 | ptr = self.head 17 | string = "TOP\n" 18 | if(self.head): 19 | while ptr: 20 | string += ("%s\n"%ptr.data) 21 | ptr = ptr.next 22 | else: 23 | string += "Empty\n" 24 | return string 25 | 26 | def push(self, element): 27 | self.head = Element(element, self.head) 28 | 29 | 30 | def pop(self): 31 | if self.empty(): return None 32 | result = self.head.data 33 | self.head = self.head.next 34 | return result 35 | 36 | def empty(self): 37 | return self.head == None 38 | 39 | if __name__ == "__main__": 40 | 41 | myS = Stack() 42 | for data in [1,2,3,4,5]: 43 | myS.push(data) 44 | 45 | print(myS) 46 | 47 | for key in ['First','Second','Third','Fourth','Fifth']: 48 | print("%s element out: %s" % (key,myS.pop())) 49 | print (myS) 50 | 51 | print("Test Empty: %s"%myS.pop()) 52 | print (myS) 53 | 54 | print("_______") 55 | for data in [1,2,3,4]: 56 | print("Adding %s" % data) 57 | myS.push(data) 58 | print(myS) 59 | print("Adding %s" % data) 60 | myS.push(data) 61 | print(myS) 62 | print("Removing %s"%myS.pop()) 63 | print(myS) 64 | 65 | print(myS) 66 | print("_______") 67 | 68 | first = myS.pop() 69 | while first != None: 70 | print("Removing %s"% first) 71 | print(myS) 72 | first = myS.pop() 73 | -------------------------------------------------------------------------------- /Graphs/ADTs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirob2005/Python_Data_Structures/2851dc124e9b52391842521e584bf5ce716f3740/Graphs/ADTs/__init__.py -------------------------------------------------------------------------------- /Graphs/DAG_Test.py: -------------------------------------------------------------------------------- 1 | from adjList import AdjList 2 | 3 | if __name__ == '__main__': 4 | 5 | print('DAG:') 6 | dag = AdjList(True) 7 | for vertex in ['r','s','t','u','v','w','x','y']: 8 | dag.addVertex(vertex) 9 | for source,dest in [('r','s'),('r','v'),('s','w'),('w','t'),('w','x'),('t','x'),('t','u'),('x','u'),('x','y'),('u','y')]: 10 | dag.addEdge(source,dest) 11 | 12 | print(dag) 13 | print('BFS:\n%s'%dag.traverseBFS('s')) 14 | print('\nDFS: %s'%dag.traverseDFS()) 15 | 16 | print('Topological Sort: %s'%dag.topologicalSort()) 17 | transpose = dag.computeTranspose() 18 | print('\nTranspose of dag:\n%s'%transpose) 19 | print('Strongly Connected Components: %s\n'%dag.stronglyConnectedComponents()) 20 | 21 | print('\nTesting Copy:\n') 22 | copy = dag.copyGraph() 23 | print(copy) 24 | print('BFS:\n%s'%copy.traverseBFS('s')) 25 | print('\nDFS:%s\n'%copy.traverseDFS()) 26 | print('Graph is a DAG: %s\n'%copy.isDAG()) 27 | 28 | print('Copy Graph after removing vertex "v"') 29 | copy.removeVertex('v') 30 | print(copy) 31 | print('DFS:%s\n'%copy.traverseDFS()) 32 | 33 | print('Compared to original graph:') 34 | print(dag) 35 | 36 | print('After Delete Vertex r:') 37 | dag.removeVertex('r') 38 | 39 | print(dag) 40 | print('BFS:\n%s'%dag.traverseBFS('s')) 41 | print('\nDFS:%s\n'%dag.traverseDFS()) 42 | 43 | print('\nAfter Delete Edge x->u:') 44 | dag.removeEdge('x','u') 45 | 46 | print(dag) 47 | print('BFS:\n%s'%dag.traverseBFS('s')) 48 | print('\nDFS:%s\n'%dag.traverseDFS()) 49 | 50 | print('Shortest Path v->y: %s'%dag.shortestPath('v','y')) 51 | print('Shortest Path s->y: %s'%dag.shortestPath('s','y')) 52 | dag.removeEdge('x','y') 53 | print('Shortest Path s-> y after delete edge x->y: %s'%dag.shortestPath('s','y')) 54 | 55 | print('\nGraph is a DAG: %s'%dag.isDAG()) 56 | 57 | print('\nCopy:\n%s'%copy) 58 | -------------------------------------------------------------------------------- /Graphs/Directed_Cycle_Test.py: -------------------------------------------------------------------------------- 1 | from adjList import AdjList 2 | 3 | if __name__ == '__main__': 4 | 5 | print('Directed Cycle:') 6 | cycle = AdjList(True) 7 | for vertex in ['r','s','t','u']: 8 | cycle.addVertex(vertex) 9 | for source,dest in [('r','s'),('s','t'),('t','r'),('t','u')]: 10 | cycle.addEdge(source,dest) 11 | 12 | print(cycle) 13 | print('BFS:\n%s'%cycle.traverseBFS('s')) 14 | print('\nDFS: %s\n'%cycle.traverseDFS()) 15 | 16 | print('Graph is a DAG: %s'%cycle.isDAG()) 17 | print('Topological Sort: %s'%cycle.topologicalSort()) 18 | print('Strongly Connected Components: %s\n'%cycle.stronglyConnectedComponents()) 19 | -------------------------------------------------------------------------------- /Graphs/README.md: -------------------------------------------------------------------------------- 1 | # *Graphs:* 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
TypeStorageAdd VertexAdd EdgeRemove VertexRemove EdgeQuery
Adjacency ListO(|V|+|E|)O(1)O(1)O(|E|)O(|E|)O(|V|)
Adjacency MatrixO(|V|^2)O(|V|^2)O(1)O(|V|^2)O(1)O(1)
Incidence ListO(|V|+|E|)O(1)O(1)O(|E|)O(|E|)O(|E|)
Incidence MatrixO(|V|*|E|)O(|V|*|E|)O(|V|*|E|)O(|V|*|E|)O(|V|*|E|)O(|E|)
20 | 21 | ## *Adjacency List:* 22 | - Vertices are stored in a dictionary. Each vertex has a list of neighboring vertices. 23 | - Supports direct and undirected graphs. 24 | 25 | ### *Operations:* 26 | - addVertex 27 | - addEdge 28 | - removeVertex 29 | - removeEdge 30 | - copyGraph 31 | 32 | ### *Algorithm:* 33 | *Breadth First Search* 34 | - traverseBFS 35 | - shortestPath 36 | 37 | *Depth First Search* 38 | - DAG test 39 | - traverseDFS 40 | - topological sort 41 | - find strongly connnected components 42 | - compute tranpose - used to find strongly connnected components 43 | - Classification of edges into: 44 | 1)Tree Edges 45 | 2)Back Edges 46 | 3)Forward/Cross Edges 47 | 48 | ## *Adjacency Matrix:* 49 | - Matrix is V rows and V columns. If a vertex V1 is adjacent to vertex V2, then the V1 row and V2 column entry in the matrix will be True or carry a weight (if weighted graph) else False or infinite weight. 50 | - If the graph is undirected the matrix will equal it's own transpose 51 | 52 | ### *Operations:* 53 | - addVertex 54 | - addEdge 55 | - removeVertex 56 | - removeEdge 57 | 58 | ### *Algorithm:* 59 | *Breadth First Search* 60 | - traverseBFS 61 | - shortestPath 62 | 63 | *Depth First Search* 64 | - traverseDFS 65 | - Classification of edges into: 66 | 1)Tree Edges 67 | 2)Back Edges 68 | 3)Forward/Cross Edges 69 | 70 | ## *Incidence List:* 71 | - Not Implemented 72 | 73 | ## *Incidence Matrix:* 74 | - Not Implemented 75 | 76 | -------------------------------------------------------------------------------- /Graphs/Undirected_Test.py: -------------------------------------------------------------------------------- 1 | from adjList import AdjList 2 | 3 | if __name__ == '__main__': 4 | 5 | print('Undirected Graph:') 6 | undirected = AdjList(False) 7 | for vertex in ['r','s','t','u','v','w','x','y']: 8 | undirected.addVertex(vertex) 9 | for source,dest in [('r','s'),('r','v'),('s','w'),('w','t'),('w','x'),('t','x'),('t','u'),('x','u'),('x','y'),('u','y')]: 10 | undirected.addEdge(source,dest) 11 | 12 | print(undirected) 13 | print('BFS:\n%s'%undirected.traverseBFS('s')) 14 | print('DFS:%s\n'%undirected.traverseDFS()) 15 | 16 | print('\nTesting Copy Undirected:') 17 | copy = undirected.copyGraph() 18 | print(copy) 19 | print('BFS:\n%s'%copy.traverseBFS('s')) 20 | print('\nDFS:%s\n'%copy.traverseDFS()) 21 | 22 | print('\nAfter Delete Vertex r:') 23 | undirected.removeVertex('r') 24 | print(undirected) 25 | print('BFS:\n%s'%undirected.traverseBFS('s')) 26 | print('\nDFS:%s\n'%undirected.traverseDFS()) 27 | 28 | print('\nAfter Delete Edge x->u:') 29 | undirected.removeEdge('x','u') 30 | print(undirected) 31 | print('BFS:\n%s'%undirected.traverseBFS('s')) 32 | print('\nDFS:%s\n'%undirected.traverseDFS()) 33 | 34 | print('Shortest Path v->y: %s'%undirected.shortestPath('v','y')) 35 | print('Shortest Path s->y: %s'%undirected.shortestPath('s','y')) 36 | undirected.removeEdge('x','y') 37 | 38 | print('Shortest Path s->y after delete edge x->y: %s'%undirected.shortestPath('s','y')) 39 | 40 | print('Graph is a DAG: %s'%undirected.isDAG()) 41 | 42 | print('\nUnchanged Copy:\n%s'%copy) 43 | copy.removeVertex('w') 44 | print('Removing vertex w:\n%s'%copy) 45 | print('BFS:\n%s'%copy.traverseBFS('s')) 46 | print('\nDFS:%s\n'%copy.traverseDFS()) 47 | 48 | print('\nOriginal Graph:\n%s'%undirected) 49 | -------------------------------------------------------------------------------- /Graphs/adjList.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 4/--/2013 4 | 5 | # Implements an Adjacency List 6 | 7 | from ADTs.Queue_head import Queue 8 | 9 | class Vertex: 10 | def __init__(self,name): 11 | self.name = name 12 | self.next = [] 13 | self.visit = None 14 | self.dist = float('inf') 15 | self.predecessor = None 16 | def __str__(self): 17 | if not self.next: 18 | string = 'Vertex %s has no outgoing edges.\n'%self.name 19 | else: 20 | string = 'Vertex %s has edges to: '%self.name 21 | for vertex in self.next: 22 | string += ('%s, '%vertex.name) 23 | string = string.rstrip(', ') + '\n' 24 | return string 25 | 26 | class AdjList: 27 | def __init__(self, directed=False): 28 | self.directed = directed 29 | self.vertexList = {} 30 | self.cycleExists = False 31 | 32 | def __str__(self): 33 | string = '' 34 | for key, value in self.vertexList.items(): 35 | string += str(value) 36 | if not string: 37 | string = '(Empty)' 38 | return string 39 | 40 | def __contains__(self,vertex): 41 | for vert in self.vertexList.keys(): 42 | if vert == vertex: 43 | return True 44 | return False 45 | 46 | def __iter__(self): 47 | return iter(self.vertexList.keys()) 48 | 49 | def addVertex(self,vertex): 50 | if vertex in self: 51 | print('Vertex %s already exists!'%vertex) 52 | return False 53 | self.vertexList[vertex] = Vertex(vertex) 54 | #print('Added vertex %s to the graph'%vertex) 55 | return True 56 | 57 | def addEdge(self,vertexFrom,vertexTo): 58 | if vertexFrom not in self: 59 | print('Vertex %s does not exist!'%vertexFrom) 60 | return False 61 | if vertexTo not in self: 62 | print('Vertex %s does not exist!'%vertexTo) 63 | return False 64 | if self.directed: 65 | self.vertexList[vertexFrom].next.append(self.vertexList[vertexTo]) 66 | #print('Added directed edge from %s to %s'%(vertexFrom,vertexTo)) 67 | else: 68 | self.vertexList[vertexFrom].next.append(self.vertexList[vertexTo]) 69 | self.vertexList[vertexTo].next.append(self.vertexList[vertexFrom]) 70 | #print('Added undirected edge from %s to %s'%(vertexFrom,vertexTo)) 71 | return True 72 | 73 | def removeVertex(self,vertex): 74 | if vertex not in self: 75 | print('Vertex %s does not exist!'%vertex) 76 | return False 77 | removed = self.vertexList.pop(vertex) 78 | for key, vertex in self.vertexList.items(): 79 | if removed in vertex.next: 80 | vertex.next.remove(removed) 81 | return True 82 | 83 | def removeEdge(self,vertexFrom,vertexTo): 84 | if vertexFrom not in self: 85 | print('Vertex %s does not exist!'%vertexFrom) 86 | return False 87 | if vertexTo not in self: 88 | print('Vertex %s does not exist!'%vertexTo) 89 | return False 90 | if self.directed: 91 | if self.vertexList[vertexTo] in self.vertexList[vertexFrom].next: 92 | self.vertexList[vertexFrom].next.remove(self.vertexList[vertexTo]) 93 | else: 94 | print('Edge %s to %s does not exist!'%(vertexFrom,vertexTo)) 95 | else: 96 | if self.vertexList[vertexTo] in self.vertexList[vertexFrom].next: 97 | self.vertexList[vertexFrom].next.remove(self.vertexList[vertexTo]) 98 | self.vertexList[vertexTo].next.remove(self.vertexList[vertexFrom]) 99 | else: 100 | print('Edge %s to %s does not exist!'%(vertexFrom,vertexTo)) 101 | return True 102 | 103 | def traverseBFS(self,source): 104 | path = '' 105 | for key, vertex in self.vertexList.items(): 106 | vertex.visit = None 107 | vertex.dist = float('inf') 108 | vertex.predecessor = None 109 | self.vertexList[source].visit = False 110 | self.vertexList[source].dist = 0 111 | self.vertexList[source].predecessor = None 112 | bfsQ = Queue() 113 | bfsQ.enQueue(self.vertexList[source]) 114 | curVertex = bfsQ.deQueue() 115 | while curVertex: 116 | for vertex in curVertex.next: 117 | if vertex.visit == None: 118 | vertex.visit = False 119 | vertex.dist = curVertex.dist+1 120 | vertex.predecessor = curVertex 121 | bfsQ.enQueue(vertex) 122 | curVertex.visit = True 123 | path+= ('Vertex %s, Distance: %s\n'%(curVertex.name,curVertex.dist)) 124 | curVertex = bfsQ.deQueue() 125 | return path 126 | 127 | def traverseDFS(self): 128 | #Used to keep track if vertex is undiscovered(None), discovered(False), 129 | # or fully explored (True) 130 | #print('Edge Classifications:') 131 | string = '' 132 | for key, vertex in self.vertexList.items(): 133 | vertex.visit = None 134 | for key, vertex in sorted(self.vertexList.items()): 135 | #If any undiscovered vertices remain, they become the new source 136 | if vertex.visit == None: 137 | string += self.DFS(vertex) 138 | return string 139 | 140 | def DFS(self,source): 141 | source.visit = False 142 | string = '(%s '%source.name 143 | for neighbor in source.next: 144 | if neighbor.visit == None: 145 | #print('Edge %s to %s is a tree edge'%(source.name,neighbor.name)) 146 | string += self.DFS(neighbor) 147 | elif neighbor.visit == False: 148 | self.cycleExists = True 149 | #print('Edge %s to %s is a back edge'%(source.name,neighbor.name)) 150 | else: 151 | pass 152 | #print('Edge %s to %s is a forward/cross edge'%(source.name,neighbor.name)) 153 | source.visit = True 154 | string += ' %s)'%source.name 155 | return string 156 | 157 | def shortestPath(self,source,dest): 158 | if not source in self: 159 | print('Vertex %s does not exist!'%source) 160 | return False 161 | if not dest in self: 162 | print('Vertex %s does not exist!'%dest) 163 | return False 164 | self.traverseBFS(source) 165 | return self.printPath(self.vertexList[source],self.vertexList[dest]) 166 | 167 | def printPath(self,source,dest): 168 | path = '' 169 | if source == dest: 170 | path += source.name 171 | elif dest.predecessor == None: 172 | print('No path exists from %s to %s'%(source.name,dest.name)) 173 | return None 174 | else: 175 | path += self.printPath(source,dest.predecessor) 176 | path += dest.name 177 | return path 178 | 179 | def isDAG(self): 180 | self.traverseDFS() 181 | return not self.cycleExists 182 | 183 | def copyGraph(self): 184 | copy = AdjList(self.directed) 185 | for key, vertex in self.vertexList.items(): 186 | vertex.visit = None 187 | for key, vertex in sorted(self.vertexList.items()): 188 | #If any undiscovered vertices remain, they become the new source 189 | if vertex.visit == None: 190 | #print('New Vertex* %s'%vertex.name) 191 | copy.vertexList[vertex.name] = Vertex(vertex.name) 192 | self.copy(vertex,copy) 193 | return copy 194 | 195 | def copy(self,source,copy): 196 | source.visit = False 197 | for neighbor in source.next: 198 | if not neighbor.name in copy.vertexList: 199 | #print('New Vertex %s'%neighbor.name) 200 | copy.vertexList[neighbor.name] = Vertex(neighbor.name) 201 | #print('Adding neighbor %s to %s'%(neighbor.name,source.name)) 202 | copy.vertexList[source.name].next.append(copy.vertexList[neighbor.name]) 203 | if neighbor.visit == None: 204 | self.copy(neighbor,copy) 205 | source.visit = True 206 | 207 | def topologicalSort(self): 208 | if not self.isDAG(): 209 | return None 210 | return self.getOrder() 211 | 212 | def DFSorder(self,source): 213 | source.visit = False 214 | order = [] 215 | for neighbor in source.next: 216 | if neighbor.visit == None: 217 | order += self.DFSorder(neighbor) 218 | source.visit = True 219 | order += [source.name] 220 | return order 221 | 222 | def stronglyConnectedComponents(self): 223 | #Get order of finishing times for normal graph 224 | order = self.getOrder() 225 | #Compute the transpose of the graph 226 | transpose = self.computeTranspose() 227 | #Traverse DFS for the tranpose using the order from the topoloical sort for the vertices 228 | components = transpose.transposeDFS(order) 229 | #Returns any strongly connected components (mutually reachable vertices) 230 | return components 231 | 232 | #Same as topological sort but ignores the DAG requirement 233 | def getOrder(self): 234 | order = [] 235 | for key, vertex in self.vertexList.items(): 236 | vertex.visit = None 237 | for key, vertex in sorted(self.vertexList.items()): 238 | #If any undiscovered vertices remain, they become the new source 239 | if vertex.visit == None: 240 | order += self.DFSorder(vertex) 241 | order.reverse() 242 | return order 243 | 244 | def transposeDFS(self,order): 245 | string = '' 246 | for key, vertex in self.vertexList.items(): 247 | vertex.visit = None 248 | #Traverse in the order of the topological sort -> 249 | # order of decreasing finishing times 250 | for vertex in order: 251 | #If any undiscovered vertices remain, they become the new source 252 | if self.vertexList[vertex].visit == None: 253 | string += self.DFS(self.vertexList[vertex]) 254 | return string 255 | 256 | def computeTranspose(self): 257 | transpose = AdjList(self.directed) 258 | for key, vertex in self.vertexList.items(): 259 | vertex.visit = None 260 | for key, vertex in sorted(self.vertexList.items()): 261 | if vertex.visit == None: 262 | transpose.vertexList[vertex.name] = Vertex(vertex.name) 263 | self.transpose(vertex,transpose) 264 | return transpose 265 | 266 | def transpose(self,source,transpose): 267 | source.visit = False 268 | for neighbor in source.next: 269 | if not neighbor.name in transpose.vertexList: 270 | transpose.vertexList[neighbor.name] = Vertex(neighbor.name) 271 | #Edge goes from the neighbor to the source (reverse of copy() for transpose) 272 | transpose.vertexList[neighbor.name].next.append(transpose.vertexList[source.name]) 273 | if neighbor.visit == None: 274 | self.transpose(neighbor,transpose) 275 | source.visit = True 276 | -------------------------------------------------------------------------------- /Graphs/adjMatrix.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 4/3/2013 4 | 5 | # Implements an Adjacency Matrix 6 | 7 | # Can declare the graph as directed/undirected in the constructor. 8 | # Undirected prohibits self-loops whereas directed does not. 9 | # Undirected affects the indices for both A->B and B->A whereas directed 10 | # only affects the direction declared in the addEdge command 11 | 12 | from ADTs.Queue_head import Queue 13 | 14 | class AdjMatrix: 15 | def __init__(self, directed=False): 16 | self.directed = directed 17 | self.matrix = [] 18 | self.vertexList = {} 19 | self.numVertices = 0 20 | 21 | def __str__(self): 22 | string = 'Dest Vert:' 23 | for key in sorted(self.vertexList, key=self.vertexList.get): 24 | string += '%7s'%key 25 | string +='\n' 26 | for key in sorted(self.vertexList, key=self.vertexList.get): 27 | string += ('Vertex \'%s\': ['%(key)) 28 | for item in self.matrix[self.vertexList[key]]: 29 | string += ('%5s, '%item) 30 | string = string.rstrip(', ')+']\n' 31 | return string 32 | 33 | def __contains__(self,vertex): 34 | return vertex in self.vertexList 35 | 36 | def __iter__(self): 37 | return iter(self.vertexList.keys()) 38 | 39 | def addVertex(self,vertex): 40 | if vertex in self.vertexList: 41 | print('Vertex %s already exists'%vertex) 42 | return False 43 | #Vertex List keeps track of the vertex name and the corresponding index 44 | # into the adjacency matrix 45 | self.vertexList[vertex] = self.numVertices 46 | self.numVertices += 1 47 | #Add row to matrix 48 | self.matrix.append([]) 49 | #Fill out matrix to be square 50 | for row in self.matrix: 51 | while len(row) != self.numVertices: 52 | row.append(False) 53 | return True 54 | 55 | def addEdge(self,vertexFrom,vertexTo): 56 | if not self.directed and vertexFrom == vertexTo: 57 | print('Undirected graph cannot have self-loops') 58 | return False 59 | try: 60 | vertexFromIndex = self.vertexList[vertexFrom] 61 | except: 62 | print('Vertex %s not found'%vertexFrom) 63 | return False 64 | try: 65 | vertexToIndex = self.vertexList[vertexTo] 66 | except: 67 | print('Vertex %s not found'%vertexTo) 68 | return False 69 | 70 | if self.directed: 71 | #Directed 72 | self.matrix[vertexFromIndex][vertexToIndex] = True 73 | else: 74 | #Undirected 75 | self.matrix[vertexFromIndex][vertexToIndex] = True 76 | self.matrix[vertexToIndex][vertexFromIndex] = True 77 | return True 78 | 79 | def removeEdge(self,vertexFrom, vertexTo): 80 | try: 81 | vertexFromIndex = self.vertexList[vertexFrom] 82 | except: 83 | print('Vertex %s not found'%vertexFrom) 84 | return False 85 | try: 86 | vertexToIndex = self.vertexList[vertexTo] 87 | except: 88 | print('Vertex %s not found'%vertexTo) 89 | return False 90 | if self.directed: 91 | #Directed 92 | self.matrix[vertexFromIndex][vertexToIndex] = False 93 | else: 94 | #Undirected 95 | self.matrix[vertexFromIndex][vertexToIndex] = False 96 | self.matrix[vertexToIndex][vertexFromIndex] = False 97 | return True 98 | 99 | def removeVertex(self,vertex): 100 | if not vertex in self.vertexList: 101 | print('Vertex %s does not exist'%vertex) 102 | return False 103 | #Remove vertex from list 104 | index = self.vertexList.pop(vertex) 105 | #Remove corresponding column from matrix 106 | for row in self.matrix: 107 | row.pop(index) 108 | #Remove corresponding row from matrix 109 | self.matrix.pop(index) 110 | self.numVertices -= 1 111 | #Reduce the index of all vertices after the removed vertex to keep 112 | # matrix and indices organized 113 | for key in self.vertexList.keys(): 114 | if self.vertexList[key] > index: 115 | self.vertexList[key] -= 1 116 | return True 117 | 118 | def traverseDFS(self): 119 | #Used to keep track if vertex is undiscovered(None), discovered(False), 120 | # or fully explored (True) 121 | visit = {} 122 | string = '' 123 | for vertex in self.vertexList.keys(): 124 | visit[vertex] = None 125 | for vertex in sorted(visit): 126 | #If any undiscovered vertices remain, they become the new source 127 | if visit[vertex] == None: 128 | string += self.DFS(vertex,visit) 129 | return string 130 | 131 | def DFS(self,source,visit): 132 | visit[source] = False 133 | string = '(%s '%source 134 | #Used to index into the adjacency matrix 135 | index = self.vertexList[source] 136 | destIndex = 0 137 | for edge in self.matrix[index]: 138 | if edge: 139 | for key,value in self.vertexList.items(): 140 | if value == destIndex: 141 | #If vertex is undiscovered 142 | if visit[key] == None: 143 | print('Edge %s to %s is a tree edge'%(source,key)) 144 | string += self.DFS(key,visit) 145 | elif visit[key] == False: 146 | print('Edge %s to %s is a back edge'%(source,key)) 147 | else: 148 | print('Edge %s to %s is a forward/cross edge'%(source,key)) 149 | destIndex+=1 150 | visit[source] = True 151 | string += ' %s)'%source 152 | return string 153 | 154 | def traverseBFS(self,source): 155 | bfsQ = Queue() 156 | distanceTo = {} 157 | if not source in self.vertexList: 158 | print('Vertex %s does not exist'%source) 159 | return False 160 | bfsQ.enQueue(source) 161 | cur = bfsQ.deQueue() 162 | distanceTo[cur] = 0 163 | while cur!=None: 164 | #Used to index into the adjacency matrix 165 | index = self.vertexList[cur] 166 | destIndex = 0 167 | for edge in self.matrix[index]: 168 | if edge: 169 | for key,value in self.vertexList.items(): 170 | if value == destIndex: 171 | #If vertex is undiscovered 172 | if not key in distanceTo: 173 | bfsQ.enQueue(key) 174 | distanceTo[key] = distanceTo[cur]+1 175 | destIndex+=1 176 | cur = bfsQ.deQueue() 177 | return distanceTo 178 | 179 | def shortestPath(self,source,dest): 180 | if not source in self.vertexList: 181 | print('Vertex %s does not exist'%source) 182 | return False 183 | if not dest in self.vertexList: 184 | print('Vertex %s does not exist'%dest) 185 | return False 186 | distance = self.traverseBFS(source) 187 | if not dest in distance: 188 | print('Vertex %s is not reachable from %s'%(dest,source)) 189 | return False 190 | return distance[dest] 191 | 192 | 193 | if __name__ == '__main__': 194 | am = AdjMatrix(True) 195 | 196 | for vertex in ['r','s','t','u','v','w','x','y']: 197 | am.addVertex(vertex) 198 | 199 | for source,dest in [('r','v'),('r','s'),('s','w'),('w','t'),('w','x'),('t','x'),('t','u'),('x','u'),('x','y'),('u','y')]: 200 | am.addEdge(source,dest) 201 | 202 | print(am) 203 | print('BFS: %s'%am.traverseBFS('r')) 204 | print('DFS: %s'%am.traverseDFS()) 205 | source = 'r' 206 | dest = 'y' 207 | print('Shortest Path from %s to %s is %s'%(source,dest,am.shortestPath(source,dest))) 208 | print('\n_________________________________\n') 209 | 210 | dfs = AdjMatrix(True) 211 | for vertex in ['y','z','s','t','x','w','v','u']: 212 | dfs.addVertex(vertex) 213 | 214 | for source,dest in [('s','z'),('z','y'),('y','x'),('x','z'),('w','x'),('z','w'),('s','w'),('v','w'),('v','s'),('t','v'),('u','v'),('u','t'),('t','u')]: 215 | dfs.addEdge(source,dest) 216 | 217 | print(dfs) 218 | print('BFS: %s'%dfs.traverseBFS('s')) 219 | print('DFS: %s'%dfs.traverseDFS()) 220 | source = 't' 221 | dest = 'y' 222 | print('Shortest Path from %s to %s is %s'%(source,dest,dfs.shortestPath(source,dest))) -------------------------------------------------------------------------------- /HashTable/HashTable.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 3/7/2013 4 | 5 | #Hash Table is built using a list of buckets, initialized to None 6 | #When an entry is added to a given bucket, the bucket stores the entries in a list 7 | #The bucket used is decided using the defined 'hash' method which returns an index 8 | # based off a hashing value modulo number of buckets in the hash table defined at 9 | # object initialization. 10 | #The hashing value is calculated as follows: 11 | # ord(character)-32*95^placement 12 | # ord returns the decimal value of the ASCII character 13 | #The printable ASCII chars are decimal 32 to 126, by subtracting 32 we get: 0 to 94 14 | #Example: key = 'test' 15 | #ord('t')-32 = 84 *95 ^0 = 84 16 | #ord('e')-32 = 69 *95 ^1 = 6555 17 | #ord('s')-32 = 83 *95 ^2 = 749075 18 | #ord('t')-32 = 84 *95 ^3 = 72019500 19 | #Hashing Value = 72019500 + 749075 + 6555 + 84 = 72775214 20 | #Index = Hashing Value % numBuckets 21 | 22 | #Results in a unique hashing value for any key 23 | 24 | #Collision are dealt using separate chaining. Each bucket contains a list of 25 | # entries with that index. 26 | 27 | 28 | class Entry: 29 | def __init__(self,key, value): 30 | self.key = key 31 | self.value = value 32 | 33 | class HashTable: 34 | def __init__(self,numBuckets): 35 | if type(numBuckets) != int or numBuckets < 0: 36 | numBuckets = 1 37 | self.numBuckets = numBuckets 38 | self.buckets = [None for x in range(0,self.numBuckets)] 39 | 40 | def __str__(self): 41 | string = '{' 42 | for bucket in self.buckets: 43 | if bucket != None: 44 | for entry in bucket: 45 | if type(entry.key) ==str: 46 | string += ("'%s': "%entry.key) 47 | else: 48 | string += ("%s: "%entry.key) 49 | if type(entry.value) ==str: 50 | string += ("'%s', "%entry.value) 51 | else: 52 | string += ("%s, "%entry.value) 53 | return string.rstrip(', ') + "}" 54 | 55 | def hash(self,key): 56 | if not key: 57 | return None 58 | power = 0 59 | hashing = 0 60 | for char in key: 61 | hashing += (ord(char)-32)*pow(95,power) 62 | power += 1 63 | index = hashing % self.numBuckets 64 | return index 65 | 66 | def add(self,key,value): 67 | index = self.hash(str(key)) 68 | if index < 0 or index > self.numBuckets: 69 | return False 70 | if self.buckets[index] == None: 71 | self.buckets[index] = [Entry(key,value)] 72 | return True 73 | else: 74 | for entry in self.buckets[index]: 75 | if entry.key == key: 76 | entry.value = value 77 | return True 78 | self.buckets[index].append(Entry(key,value)) 79 | return True 80 | 81 | def updateValue(self,key,value): 82 | index = self.hash(str(key)) 83 | if index == None: 84 | return False 85 | if self.buckets[index] == None: 86 | #print("Key Not Found!") 87 | return False 88 | else: 89 | for entry in self.buckets[index]: 90 | if entry.key == key: 91 | entry.value = value 92 | return True 93 | #print("Key Not Found!") 94 | return False 95 | 96 | def delete(self,key): 97 | index = self.hash(str(key)) 98 | if index == None: 99 | return False 100 | if self.buckets[index] == None: 101 | #print("Key Not Found!") 102 | return False 103 | else: 104 | for entry in self.buckets[index]: 105 | if entry.key == key: 106 | self.buckets[index].remove(entry) 107 | return True 108 | #print("Key Not Found!") 109 | return False 110 | 111 | def lookUp(self,key): 112 | index = self.hash(str(key)) 113 | if index == None: 114 | return False 115 | if self.buckets[index] == None: 116 | #print("Key Not Found!") 117 | return False 118 | else: 119 | for entry in self.buckets[index]: 120 | if entry.key == key: 121 | return entry.value 122 | #print("Key Not Found!") 123 | return False 124 | 125 | def printDistribution(self): 126 | string = '' 127 | bucketNum = 0 128 | MIN = None 129 | MAX = 0 130 | TOTAL = 0 131 | for bucket in self.buckets: 132 | if bucket != None: 133 | #string += ("Bucket Number %d has: "%bucketNum) 134 | count = 0 135 | for entry in bucket: 136 | count += 1 137 | #string += ("%d entries\n"%count) 138 | TOTAL += count 139 | if count > MAX: 140 | MAX = count 141 | if MIN == None or count < MIN: 142 | MIN = count 143 | else: 144 | pass 145 | #string += ("Bucket Number %d has 0 entries\n"%(bucketNum)) 146 | bucketNum +=1 147 | string += ("Largest Bucket has %d entries\n"\ 148 | "Smallest Bucket has %d entries\nTotal entries: %d\n"\ 149 | "Avg bucket size is %f"%(MAX,MIN,TOTAL,(TOTAL/self.numBuckets))) 150 | return string 151 | 152 | if __name__ == '__main__': 153 | ht = HashTable(100) 154 | 155 | print(ht) 156 | 157 | ht.add('bob',2) 158 | ht.add(11,3) 159 | ht.add('11',4) 160 | 161 | ht.add(' ',5) 162 | print(ht) 163 | 164 | print() 165 | print(ht.lookUp(11)) 166 | #print(ht.printDistribution()) -------------------------------------------------------------------------------- /HashTable/HashTable_UnitTests.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 3/7/2013 4 | 5 | from HashTable import HashTable 6 | import unittest 7 | 8 | class TestHashTable(unittest.TestCase): 9 | 10 | def setUp(self): 11 | self.empty = HashTable(100) 12 | self.oneBucket = HashTable(1) 13 | self.tenBuckets = HashTable(10) 14 | self.hundredBuckets = HashTable(100) 15 | 16 | self.hashes = [[self.oneBucket,'One Bucket'], [self.tenBuckets,'Ten Buckets'], [self.hundredBuckets,'100 Buckets']] 17 | 18 | def testEmpty(self): 19 | self.assertEqual(self.empty.__str__(),"{}") 20 | self.assertFalse(self.empty.delete('DeleteMe')) 21 | self.assertFalse(self.empty.lookUp('FindMe')) 22 | self.assertFalse(self.empty.updateValue('UpdateMe', 'ToThis')) 23 | 24 | self.assertTrue(self.empty.add('AddMe',2)) 25 | self.assertEqual(self.empty.__str__(),"{'AddMe': 2}") 26 | 27 | print('\ntestEmpty PASSED') 28 | 29 | def testAdd(self): 30 | for ht,name in self.hashes: 31 | self.assertTrue(ht.add('AddMe',2)) 32 | self.assertEqual(ht.__str__(),"{'AddMe': 2}") 33 | 34 | self.assertTrue(ht.add('AddMe',3)) 35 | self.assertEqual(ht.__str__(),"{'AddMe': 3}") 36 | 37 | self.assertTrue(ht.add('2ndItem',4)) 38 | expResult1 = "\{'AddMe': 3, '2ndItem': 4\}" 39 | expResult2= "\{'2ndItem': 4, 'AddMe': 3\}" 40 | self.assertRegex(ht.__str__(), ('%s|%s' %(expResult1,expResult2))) 41 | 42 | print('\ntestAdd on %s PASSED'%name) 43 | 44 | def testDelete(self): 45 | for ht,name in self.hashes: 46 | self.assertTrue(ht.add('AddMe',2)) 47 | self.assertEqual(ht.__str__(),"{'AddMe': 2}") 48 | 49 | self.assertTrue(ht.add('AddMe',3)) 50 | self.assertEqual(ht.__str__(),"{'AddMe': 3}") 51 | 52 | self.assertTrue(ht.add('2ndItem',4)) 53 | expResult1 = "\{'AddMe': 3, '2ndItem': 4\}" 54 | expResult2= "\{'2ndItem': 4, 'AddMe': 3\}" 55 | self.assertRegex(ht.__str__(), ('%s|%s' %(expResult1,expResult2))) 56 | 57 | self.assertTrue(ht.delete('AddMe')) 58 | self.assertEqual(ht.__str__(),"{'2ndItem': 4}") 59 | 60 | self.assertFalse(ht.delete('AddMe')) 61 | self.assertTrue(ht.delete('2ndItem')) 62 | 63 | self.assertEqual(ht.__str__(),"{}") 64 | 65 | print('\ntestDelete on %s PASSED'%name) 66 | 67 | def testLookUp(self): 68 | for ht,name in self.hashes: 69 | self.assertTrue(ht.add('AddMe',3)) 70 | self.assertEqual(ht.__str__(),"{'AddMe': 3}") 71 | 72 | self.assertTrue(ht.add('2ndItem',4)) 73 | expResult1 = "\{'AddMe': 3, '2ndItem': 4\}" 74 | expResult2= "\{'2ndItem': 4, 'AddMe': 3\}" 75 | self.assertRegex(ht.__str__(), ('%s|%s' %(expResult1,expResult2))) 76 | 77 | self.assertEqual(ht.lookUp('AddMe'), 3) 78 | self.assertEqual(ht.lookUp('2ndItem'), 4) 79 | 80 | self.assertFalse(ht.lookUp('missing')) 81 | 82 | print('\ntestLookUp on %s PASSED'%name) 83 | 84 | def testUpdate(self): 85 | for ht,name in self.hashes: 86 | self.assertTrue(ht.add('AddMe',3)) 87 | self.assertEqual(ht.__str__(),"{'AddMe': 3}") 88 | 89 | self.assertTrue(ht.add('2ndItem',4)) 90 | expResult1 = "\{'AddMe': 3, '2ndItem': 4\}" 91 | expResult2= "\{'2ndItem': 4, 'AddMe': 3\}" 92 | self.assertRegex(ht.__str__(), ('%s|%s' %(expResult1,expResult2))) 93 | 94 | self.assertTrue(ht.updateValue('AddMe', 4)) 95 | expResult1 = "\{'AddMe': 4, '2ndItem': 4\}" 96 | expResult2= "\{'2ndItem': 4, 'AddMe': 4\}" 97 | self.assertRegex(ht.__str__(), ('%s|%s' %(expResult1,expResult2))) 98 | 99 | self.assertFalse(ht.updateValue('missing',4)) 100 | 101 | print('\ntestUpdate on %s PASSED'%name) 102 | 103 | def testHashing(self): 104 | key = 'test' 105 | hashing = (ord('t')-32) + (ord('e')-32)*95 + (ord('s')-32)*95*95 + (ord('t')-32)*95*95*95 106 | self.assertEqual(hashing, 72775214) 107 | self.assertEqual(hashing%1, 0) 108 | self.assertEqual(hashing%10, 4) 109 | self.assertEqual(hashing%100, 14) 110 | 111 | key2 = '~ ' 112 | hashing2 = (ord('~')-32) + (ord(' ')-32)*95 113 | self.assertEqual(hashing2, 94) 114 | for ht,name in self.hashes: 115 | self.assertEqual(ht.hash(''), None) 116 | self.assertEqual(ht.hash(key), hashing%ht.numBuckets) 117 | self.assertEqual(ht.hash(key2), hashing2%ht.numBuckets) 118 | 119 | print('\ntestHashing on %s PASSED'%name) 120 | 121 | def testKeyType(self): 122 | for ht,name in self.hashes: 123 | self.assertTrue(ht.add('11','2')) 124 | self.assertEqual(ht.__str__(),"{'11': '2'}") 125 | 126 | self.assertTrue(ht.add(11,3)) 127 | expResult1 = "\{'11': '2', 11: 3\}" 128 | expResult2= "\{11: 3, '11': '2'\}" 129 | self.assertRegex(ht.__str__(), ('%s|%s' %(expResult1,expResult2))) 130 | 131 | self.assertEqual(ht.lookUp('11'),'2') 132 | self.assertEqual(ht.lookUp(11),3) 133 | 134 | self.assertTrue(ht.updateValue('11',2)) 135 | expResult1 = "\{'11': 2, 11: 3\}" 136 | expResult2= "\{11: 3, '11': 2\}" 137 | self.assertRegex(ht.__str__(), ('%s|%s' %(expResult1,expResult2))) 138 | self.assertEqual(ht.lookUp('11'),2) 139 | 140 | self.assertTrue(ht.updateValue(11,'3')) 141 | expResult1 = "\{'11': 2, 11: '3'\}" 142 | expResult2= "\{11: '3', '11': 2\}" 143 | self.assertRegex(ht.__str__(), ('%s|%s' %(expResult1,expResult2))) 144 | self.assertEqual(ht.lookUp(11),'3') 145 | 146 | self.assertTrue(ht.delete(11)) 147 | self.assertEqual(ht.__str__(),"{'11': 2}") 148 | 149 | self.assertFalse(ht.delete(11)) 150 | 151 | self.assertTrue(ht.delete('11')) 152 | self.assertEqual(ht.__str__(),"{}") 153 | print('\ntestKeyType on %s PASSED'%name) 154 | 155 | if __name__ == '__main__': 156 | unittest.main() -------------------------------------------------------------------------------- /HashTable/Hash_Dist_Tester.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 3/5/2013 4 | 5 | #Distribution: 6 | #100 Buckets 7 | #LOW: 507 entries 8 | #HIGH: 3715 entries 9 | #TOTAL: 147644 entries 10 | #Load Factor: 1476.44 entries per bucket 11 | #Time to ADD ALL: 55.77 seconds 12 | 13 | 14 | #1,000 Buckets 15 | #LOW: 36 entries 16 | #HIGH: 413 entries 17 | #TOTAL: 147644 entries 18 | #Load Factor: 147.644 entries per bucket 19 | #Time to ADD ALL: 6.49 seconds 20 | 21 | #10,000 Buckets 22 | #LOW: 1 entries 23 | #HIGH: 59 entries 24 | #TOTAL: 147644 entries 25 | #Load Factor: 14.7644 entries per bucket 26 | #Time to ADD ALL: 3.98 seconds 27 | 28 | #100,000 Buckets 29 | #LOW: 1 entries 30 | #HIGH: 12 entries 31 | #TOTAL: 147644 entries 32 | #Load Factor: 1.47644 entries per bucket 33 | #Time to ADD ALL: 3.84 seconds 34 | 35 | import time 36 | from HashTable import HashTable 37 | 38 | fileIn = open('../Lorem_ipsum.txt','r').read() 39 | words = fileIn.split(' ') 40 | 41 | start1 = time.clock() 42 | print("HashTable(100) start time:%f"%start1) 43 | ht = HashTable(100) 44 | 45 | wordCount = 0 46 | for word in words: 47 | ht.add(str(wordCount)+word, wordCount) 48 | wordCount += 1 49 | add1 = time.clock() 50 | print("HashTable(100) add time:%f\n"%(add1-start1)) 51 | 52 | print(ht.printDistribution()) 53 | 54 | print('\n') 55 | 56 | start2 = time.clock() 57 | print("HashTable(1000) start time:%f"%start2) 58 | ht2 = HashTable(1000) 59 | 60 | wordCount = 0 61 | for word in words: 62 | ht2.add(str(wordCount)+word, wordCount) 63 | wordCount += 1 64 | add2 = time.clock() 65 | print("HashTable(1000) add time:%f"%(add2-start2)) 66 | print(ht2.printDistribution()) 67 | 68 | print('\n') 69 | 70 | start3 = time.clock() 71 | print("HashTable(10000) start time:%f"%start3) 72 | ht3 = HashTable(10000) 73 | 74 | wordCount = 0 75 | for word in words: 76 | ht3.add(str(wordCount)+word, wordCount) 77 | wordCount += 1 78 | add3 = time.clock() 79 | print("HashTable(10000) add time:%f"%(add3-start3)) 80 | print(ht3.printDistribution()) 81 | 82 | print('\n') 83 | 84 | start4 = time.clock() 85 | print("HashTable(100000) start time:%f"%start4) 86 | ht4 = HashTable(100000) 87 | 88 | wordCount = 0 89 | for word in words: 90 | ht4.add(str(wordCount)+word, wordCount) 91 | wordCount += 1 92 | add4 = time.clock() 93 | print("HashTable(100000) add time:%f"%(add4-start4)) 94 | print(ht4.printDistribution()) -------------------------------------------------------------------------------- /HashTable/README.md: -------------------------------------------------------------------------------- 1 | # *Hash Table:* 2 | ## *Operations:* 3 | - add 4 | - updateValue 5 | - delete 6 | - lookUp 7 | - hash 8 | 9 | ### *Hashing Operation:* 10 | -------------------------------------------------------------------------------- /LinkedLists/LinkedList_Circular.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/13/2013 4 | 5 | # Typical Circular Linked List with head and tail ptr. Common operations included. 6 | # Inherits __init__ from DoublyNode 7 | 8 | from LinkedList_Double import DoublyNode 9 | 10 | class CircularNode(DoublyNode): 11 | pass 12 | 13 | class CircularLinkedList: 14 | def __init__(self): 15 | self.head = None 16 | self.tail = None 17 | 18 | def __str__(self): 19 | if(self.head != None): 20 | string = ("HEAD(%d) <"%self.head.data) 21 | else: 22 | string = ("HEAD(None) <") 23 | ptr = self.head 24 | if(ptr != None): 25 | while True: 26 | if(ptr == self.head): 27 | string += " " 28 | if(ptr.prev == None): 29 | string += "(None)<-[" 30 | else: 31 | string += "("+ str(ptr.prev.data)+ ")<-[" 32 | string += str(ptr.data) 33 | if(ptr.next == None): 34 | string+="]->(None)" 35 | else: 36 | string += "]->("+str(ptr.next.data)+") " 37 | ptr = ptr.next 38 | if(ptr == self.head): break 39 | if(self.tail != None): 40 | string+=("> TAIL(%d)"%self.tail.data) 41 | else: 42 | string+= "> TAIL(None)" 43 | return string 44 | 45 | def insert(self, data): 46 | if(self.head==None): 47 | self.head = CircularNode(data,None,None) 48 | self.head.next = self.head 49 | self.head.prev = self.head 50 | self.tail = self.head 51 | else: 52 | oldHead = self.head 53 | self.head = CircularNode(data,self.head, self.tail) 54 | oldHead.prev = self.head 55 | self.tail.next = self.head 56 | 57 | def append(self, data): 58 | ptr = self.head 59 | if(ptr == None): 60 | self.insert(data) 61 | else: 62 | while ptr.next != self.head: 63 | ptr=ptr.next 64 | ptr.next = CircularNode(data, self.head, ptr) 65 | self.tail = ptr.next 66 | self.head.prev = self.tail 67 | 68 | def returnIndex(self, data): 69 | ptr = self.head 70 | index = 0 71 | if(ptr != None): 72 | while True: 73 | if(ptr.data == data): 74 | return index 75 | index += 1 76 | ptr=ptr.next 77 | if(ptr == self.head): break 78 | return None 79 | 80 | def updateIndex(self,index,data): 81 | if(index <0 or self.head == None): 82 | return False 83 | currentIndex = 0 84 | ptr = self.head 85 | while True: 86 | if(currentIndex == index): 87 | ptr.data = data 88 | return True 89 | currentIndex+=1 90 | ptr=ptr.next 91 | if(ptr == self.head): break 92 | return False 93 | 94 | def deleteIndex(self, index): 95 | if(index<0 or self.head == None): 96 | return False 97 | ptr = self.head 98 | if(index==0): 99 | if(self.head == self.head.next): 100 | self.head.next = None 101 | self.head.prev = None 102 | self.tail.next = None 103 | self.tail.prev = None 104 | self.tail = None 105 | self.head = None 106 | return True 107 | else: 108 | self.head = self.head.next 109 | ptr.next = None 110 | ptr.prev = None 111 | self.head.prev = self.tail 112 | self.tail.next = self.head 113 | return True 114 | currentIndex=0 115 | while ptr.next != self.head: 116 | if(currentIndex+1 == index): 117 | self.deletePtr(ptr) 118 | return True 119 | ptr=ptr.next 120 | currentIndex+=1 121 | return False 122 | 123 | def insertBeforeIndex(self,index,data): 124 | if(index==0): 125 | self.insert(data) 126 | return True 127 | if(index <0 or self.head == None): 128 | return False 129 | ptr=self.head 130 | currentIndex=0 131 | while True: 132 | if(currentIndex+1 == index): 133 | ptr.next = CircularNode(data,ptr.next,ptr) 134 | if(ptr == self.tail): 135 | self.tail = ptr.next 136 | ptr.next.next.prev = ptr.next 137 | return True 138 | currentIndex+=1 139 | ptr=ptr.next 140 | if(ptr == self.head): break 141 | return False 142 | 143 | def insertAfterIndex(self,index,data): 144 | if(index ==-1): 145 | self.insert(data) 146 | return True 147 | if(index <-1 or self.head == None): 148 | return False 149 | currentIndex=0 150 | ptr=self.head 151 | while True: 152 | if(currentIndex==index): 153 | ptr.next = CircularNode(data,ptr.next,ptr) 154 | if(ptr == self.tail): 155 | self.tail = ptr.next 156 | ptr.next.next.prev = ptr.next 157 | return True 158 | currentIndex+=1 159 | ptr=ptr.next 160 | if(ptr == self.head): break 161 | return False 162 | 163 | def deleteData(self, data): 164 | ptr = self.head 165 | if(ptr == None): 166 | return False 167 | if(self.head.data == data): 168 | if(self.head == self.head.next): 169 | self.head.next = None 170 | self.head.prev = None 171 | self.tail.next = None 172 | self.tail.prev = None 173 | self.tail = None 174 | self.head = None 175 | return True 176 | else: 177 | self.head = self.head.next 178 | ptr.next = None 179 | ptr.prev = None 180 | self.head.prev = self.tail 181 | self.tail.next = self.head 182 | return True 183 | while ptr.next != self.head: 184 | if(ptr.next.data == data): 185 | self.deletePtr(ptr) 186 | return True 187 | ptr = ptr.next 188 | return False 189 | 190 | def deletePtr(self, ptr): 191 | if(ptr.next == self.tail): 192 | self.tail = ptr 193 | tempptr = ptr.next.next 194 | ptr.next.prev = None 195 | ptr.next.next = None 196 | ptr.next = tempptr 197 | if(ptr.next != None): 198 | ptr.next.prev = ptr 199 | 200 | def deleteAllData(self,data): 201 | success = self.deleteData(data) 202 | if(success): 203 | while(self.deleteData(data)): 204 | continue 205 | return success 206 | 207 | def insertAfterEveryData(self,data,dataToInsert): 208 | if(self.head == None): 209 | return False 210 | success = False 211 | ptr = self.head 212 | while True: 213 | if(ptr.data == data): 214 | ptr.next = CircularNode(dataToInsert,ptr.next,ptr) 215 | if(ptr == self.tail): 216 | self.tail = ptr.next 217 | ptr.next.next.prev = ptr.next 218 | success = True 219 | ptr = ptr.next 220 | ptr = ptr.next 221 | if(ptr == self.head): break 222 | return success 223 | 224 | def insertBeforeEveryData(self,data,dataToInsert): 225 | if(self.head == None): 226 | return False 227 | success = False 228 | if(self.head.data == data): 229 | success = True 230 | self.insert(dataToInsert) 231 | ptr = self.head.next 232 | else: 233 | ptr = self.head 234 | while ptr.next != self.head: 235 | if(ptr.next.data == data): 236 | ptr.next = CircularNode(dataToInsert,ptr.next,ptr) 237 | if(ptr.next.next != None): 238 | ptr.next.next.prev = ptr.next 239 | success = True 240 | ptr = ptr.next 241 | ptr = ptr.next 242 | return success 243 | 244 | def deleteList(self): 245 | ptr = self.head 246 | while self.head.next != self.head and self.head.prev != self.head: 247 | #print("\nDeleting %d" % self.head.data) 248 | self.head = self.head.next 249 | ptr.next = None 250 | ptr.prev = None 251 | self.head.prev = self.tail 252 | self.tail.next = self.head 253 | ptr = self.head 254 | #print("\t%s" % self) 255 | #print("\nDeleting %d" % self.head.data) 256 | self.head.next = None 257 | self.head.prev = None 258 | self.tail.next = None 259 | self.tail.prev = None 260 | self.head = None 261 | self.tail = None 262 | 263 | def copyList(self): 264 | copy = CircularLinkedList() 265 | 266 | ptr = self.head 267 | while True: 268 | copy.append(ptr.data) 269 | ptr = ptr.next 270 | if(ptr == self.head): break 271 | return copy 272 | 273 | def findMthToLastNode(self, M): 274 | if(M <= 0): 275 | return None 276 | ptr = self.tail 277 | for x in range(1,M): 278 | ptr = ptr.prev 279 | if(ptr == self.tail): 280 | return None 281 | return ptr.data 282 | 283 | 284 | if __name__ == '__main__': 285 | alist = CircularLinkedList() 286 | 287 | for data in [4,3,2,1]: 288 | alist.insert(data) 289 | 290 | print(alist) -------------------------------------------------------------------------------- /LinkedLists/LinkedList_Double.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/13/2013 4 | 5 | # Typical Double Linked List with head ptr only. Common operations included. 6 | # Inherits __init__ , returnIndex(index), updateIndex(index), findMthToLastNode(M) 7 | # from Single Linked List. 8 | 9 | from LinkedList_Single import LinkedList 10 | from LinkedList_Single import Node 11 | 12 | class DoublyNode(Node): 13 | def __init__(self, data, next, prev): 14 | self.data = data 15 | self.next = next 16 | self.prev = prev 17 | 18 | class DoublyLinkedList(LinkedList): 19 | 20 | def __str__(self): 21 | ptr = self.head 22 | string = "HEAD <" 23 | while ptr: 24 | if(ptr == self.head): 25 | string += " " 26 | if(ptr.prev == None): 27 | string += "(None)<-[" 28 | else: 29 | string += "("+ str(ptr.prev.data)+ ")<-[" 30 | string += str(ptr.data) 31 | if(ptr.next == None): 32 | string+="]->(None) " 33 | else: 34 | string += "]->("+str(ptr.next.data)+") " 35 | ptr = ptr.next 36 | return string + "> TAIL" 37 | 38 | def insert(self, data): 39 | if(self.head==None): 40 | self.head = DoublyNode(data,self.head, None) 41 | else: 42 | oldHead = self.head 43 | self.head = DoublyNode(data,self.head, None) 44 | oldHead.prev = self.head 45 | 46 | def append(self, data): 47 | ptr = self.head 48 | if(ptr == None): 49 | self.insert(data) 50 | else: 51 | while ptr.next: 52 | ptr=ptr.next 53 | ptr.next = DoublyNode(data, None, ptr) 54 | 55 | def insertBeforeIndex(self,index,data): 56 | if(index <0): 57 | return False 58 | if(index==0): 59 | self.insert(data) 60 | return True 61 | ptr=self.head 62 | currentIndex=0 63 | while ptr: 64 | if(currentIndex+1 == index): 65 | ptr.next = DoublyNode(data,ptr.next,ptr) 66 | if(ptr.next.next != None): 67 | ptr.next.next.prev = ptr.next 68 | return True 69 | currentIndex+=1 70 | ptr=ptr.next 71 | return False 72 | 73 | def insertAfterIndex(self,index,data): 74 | if(index <-1): 75 | return False 76 | if(index ==-1): 77 | self.insert(data) 78 | return True 79 | currentIndex=0 80 | ptr=self.head 81 | while ptr: 82 | if(currentIndex==index): 83 | ptr.next = DoublyNode(data,ptr.next,ptr) 84 | if(ptr.next.next != None): 85 | ptr.next.next.prev = ptr.next 86 | return True 87 | currentIndex+=1 88 | ptr=ptr.next 89 | return False 90 | 91 | def deleteIndex(self, index): 92 | if(index<0 or self.head == None): 93 | return False 94 | ptr = self.head 95 | if(index==0): 96 | self.head = self.head.next 97 | ptr.next = None 98 | if(self.head != None): 99 | self.head.prev = None 100 | return True 101 | currentIndex=0 102 | while ptr.next: 103 | if(currentIndex+1 == index): 104 | self.deletePtr(ptr) 105 | return True 106 | ptr=ptr.next 107 | currentIndex+=1 108 | return False 109 | 110 | def deleteData(self, data): 111 | ptr = self.head 112 | if(ptr == None): 113 | return False 114 | if(self.head.data == data): 115 | self.head = self.head.next 116 | ptr.next = None 117 | if(self.head != None): 118 | self.head.prev = None 119 | return True 120 | while ptr.next: 121 | if(ptr.next.data == data): 122 | self.deletePtr(ptr) 123 | return True 124 | ptr = ptr.next 125 | return False 126 | 127 | def deletePtr(self, ptr): 128 | tempptr = ptr.next.next 129 | ptr.next.prev = None 130 | ptr.next.next = None 131 | ptr.next = tempptr 132 | if(ptr.next != None): 133 | ptr.next.prev = ptr 134 | 135 | def deleteAllData(self,data): 136 | success = self.deleteData(data) 137 | if(success): 138 | while(self.deleteData(data)): 139 | continue 140 | return success 141 | 142 | def deleteList(self): 143 | ptr = self.head 144 | while self.head: 145 | #print("\nDeleting %d" % self.head.data) 146 | self.head = self.head.next 147 | ptr.next = None 148 | if(self.head != None): self.head.prev = None 149 | ptr = self.head 150 | #print("\t%s" % self) 151 | self.head = None 152 | 153 | def copyList(self): 154 | copy = DoublyLinkedList() 155 | 156 | ptr = self.head 157 | while ptr: 158 | copy.append(ptr.data) 159 | ptr = ptr.next 160 | 161 | return copy 162 | 163 | def insertAfterEveryData(self,data,dataToInsert): 164 | if(self.head == None): 165 | return False 166 | success = False 167 | ptr = self.head 168 | while ptr: 169 | if(ptr.data == data): 170 | ptr.next = DoublyNode(dataToInsert,ptr.next,ptr) 171 | if(ptr.next.next != None): 172 | ptr.next.next.prev = ptr.next 173 | success = True 174 | ptr = ptr.next 175 | ptr = ptr.next 176 | return success 177 | 178 | def insertBeforeEveryData(self,data,dataToInsert): 179 | if(self.head == None): 180 | return False 181 | success = False 182 | if(self.head.data == data): 183 | success = True 184 | self.insert(dataToInsert) 185 | ptr = self.head.next 186 | else: 187 | ptr = self.head 188 | while ptr.next: 189 | if(ptr.next.data == data): 190 | ptr.next = DoublyNode(dataToInsert,ptr.next,ptr) 191 | if(ptr.next.next != None): 192 | ptr.next.next.prev = ptr.next 193 | success = True 194 | ptr = ptr.next 195 | ptr = ptr.next 196 | return success 197 | 198 | if __name__ == '__main__': 199 | alist = DoublyLinkedList() 200 | 201 | for data in [4,3,2,1]: 202 | alist.insert(data) 203 | print(alist) -------------------------------------------------------------------------------- /LinkedLists/LinkedList_Single.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/13/2013 4 | 5 | # Typical Single Linked List with head ptr only. Common operations included. 6 | 7 | class Node: 8 | def __init__(self, data, next): 9 | self.data = data 10 | self.next = next 11 | 12 | class LinkedList: 13 | def __init__(self): 14 | self.head = None 15 | 16 | def __str__(self): 17 | ptr = self.head 18 | string = "HEAD <" 19 | while ptr: 20 | if(ptr == self.head): 21 | string += " " 22 | string += "["+ str(ptr.data) 23 | if(ptr.next == None): 24 | string+="]->(None) " 25 | else: 26 | string += "]->("+str(ptr.next.data)+") " 27 | ptr = ptr.next 28 | return string + "> TAIL" 29 | 30 | def insert(self, data): 31 | self.head = Node(data,self.head) 32 | 33 | def append(self, data): 34 | ptr = self.head 35 | if(ptr == None): 36 | self.insert(data) 37 | else: 38 | while ptr.next: 39 | ptr=ptr.next 40 | ptr.next = Node(data, None) 41 | 42 | def returnIndex(self, data): 43 | ptr = self.head 44 | index = 0 45 | while ptr: 46 | if(ptr.data == data): 47 | return index 48 | index += 1 49 | ptr=ptr.next 50 | return None 51 | 52 | def updateIndex(self,index,data): 53 | if(index<0 or self.head == None): 54 | return False 55 | currentIndex = 0 56 | ptr = self.head 57 | while ptr: 58 | if(currentIndex == index): 59 | ptr.data = data 60 | return True 61 | currentIndex+=1 62 | ptr=ptr.next 63 | return False 64 | 65 | def deleteIndex(self, index): 66 | if(index<0 or self.head == None): 67 | return False 68 | ptr=self.head 69 | if(index==0): 70 | self.head = self.head.next 71 | ptr.next = None 72 | return True 73 | currentIndex=0 74 | while ptr.next: 75 | if(currentIndex+1 == index): 76 | self.deletePtr(ptr) 77 | return True 78 | ptr=ptr.next 79 | currentIndex+=1 80 | return False 81 | 82 | def insertBeforeIndex(self,index,data): 83 | if(index <0): 84 | return False 85 | if(index==0): 86 | self.insert(data) 87 | return True 88 | ptr=self.head 89 | currentIndex=0 90 | while ptr: 91 | if(currentIndex+1 == index): 92 | ptr.next = Node(data,ptr.next) 93 | return True 94 | currentIndex+=1 95 | ptr=ptr.next 96 | return False 97 | 98 | def insertAfterIndex(self,index,data): 99 | if(index <-1): 100 | return False 101 | if(index ==-1): 102 | self.insert(data) 103 | return True 104 | currentIndex=0 105 | ptr=self.head 106 | while ptr: 107 | if(currentIndex==index): 108 | ptr.next = Node(data,ptr.next) 109 | return True 110 | currentIndex+=1 111 | ptr=ptr.next 112 | return False 113 | 114 | def deleteData(self, data): 115 | ptr = self.head 116 | if(ptr == None): 117 | return False 118 | if(self.head.data == data): 119 | self.head = self.head.next 120 | ptr.next = None 121 | return True 122 | while ptr.next: 123 | if(ptr.next.data == data): 124 | self.deletePtr(ptr) 125 | return True 126 | ptr = ptr.next 127 | return False 128 | 129 | def deletePtr(self,ptr): 130 | tempptr = ptr.next.next 131 | ptr.next.next = None 132 | ptr.next = tempptr 133 | 134 | def deleteAllData(self,data): 135 | success = self.deleteData(data) 136 | if(success): 137 | while(self.deleteData(data)): 138 | continue 139 | return success 140 | 141 | def insertAfterEveryData(self,data,dataToInsert): 142 | if(self.head == None): 143 | return False 144 | success = False 145 | ptr = self.head 146 | while ptr: 147 | if(ptr.data == data): 148 | ptr.next = Node(dataToInsert,ptr.next) 149 | success = True 150 | ptr = ptr.next 151 | ptr = ptr.next 152 | return success 153 | 154 | def insertBeforeEveryData(self,data,dataToInsert): 155 | if(self.head == None): 156 | return False 157 | success = False 158 | if(self.head.data == data): 159 | success = True 160 | self.insert(dataToInsert) 161 | ptr = self.head.next 162 | else: 163 | ptr = self.head 164 | while ptr.next: 165 | if(ptr.next.data == data): 166 | ptr.next = Node(dataToInsert,ptr.next) 167 | success = True 168 | ptr = ptr.next 169 | ptr = ptr.next 170 | return success 171 | 172 | def deleteList(self): 173 | ptr = self.head 174 | while self.head: 175 | #print("\nDeleting %d" % self.head.data) 176 | self.head = self.head.next 177 | ptr.next = None 178 | ptr = self.head 179 | #print("\t%s" % self) 180 | self.head = None 181 | 182 | def copyList(self): 183 | copy = LinkedList() 184 | 185 | ptr = self.head 186 | while ptr: 187 | copy.append(ptr.data) 188 | ptr = ptr.next 189 | 190 | return copy 191 | 192 | def findMthToLastNode(self, M): 193 | if(M <= 0): 194 | return None 195 | ptr = self.head 196 | mBehindPtr = self.head 197 | for i in range(0,M,1): 198 | if(ptr == None): 199 | return None 200 | ptr = ptr.next 201 | while ptr: 202 | ptr = ptr.next 203 | mBehindPtr = mBehindPtr.next 204 | return mBehindPtr.data 205 | 206 | if __name__ == '__main__': 207 | alist = LinkedList() 208 | 209 | for data in [0,3,0,1]: 210 | alist.insert(data) 211 | print(alist) -------------------------------------------------------------------------------- /LinkedLists/LinkedList_Single_UnitTests.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/13/2013 4 | 5 | from LinkedList_Single import LinkedList 6 | from LinkedList_Single import Node 7 | import unittest 8 | 9 | class TestLinkedListSingle(unittest.TestCase): 10 | 11 | def setUp(self): 12 | self.A = LinkedList() 13 | for data in [3,2,1]: 14 | self.A.insert(data) 15 | 16 | def testEmpty(self): 17 | emptyList = LinkedList() 18 | expResult = "HEAD <> TAIL" 19 | result = str(emptyList) 20 | self.assertEqual(result, expResult) 21 | print("\ntestEmpty PASSED!") 22 | 23 | def testInsert(self): 24 | expResult = "HEAD < [1]->(2) [2]->(3) [3]->(None) > TAIL" 25 | result = str(self.A) 26 | self.assertEqual(result, expResult) 27 | print("\ntestInsert PASSED!") 28 | 29 | def testAppend(self): 30 | self.A.append(4) 31 | 32 | expResult = "HEAD < [1]->(2) [2]->(3) [3]->(4) [4]->(None) > TAIL" 33 | result = str(self.A) 34 | self.assertEqual(result, expResult) 35 | print("\ntestAppend PASSED!") 36 | 37 | def testReturnIndex(self): 38 | result = self.A.returnIndex(1) 39 | expResult = 0 40 | self.assertEqual(result, expResult) 41 | print("\ntestReturnIndex #1 PASSED!") 42 | 43 | result = self.A.returnIndex(2) 44 | expResult = 1 45 | self.assertEqual(result, expResult) 46 | print("\ntestReturnIndex #2 PASSED!") 47 | 48 | result = self.A.returnIndex(3) 49 | expResult = 2 50 | self.assertEqual(result, expResult) 51 | print("\ntestReturnIndex #3 PASSED!") 52 | 53 | result = self.A.returnIndex(4) 54 | expResult = None 55 | self.assertEqual(result, expResult) 56 | print("\ntestReturnIndex #4 PASSED!") 57 | 58 | def testUpdateIndex(self): 59 | boolResult = self.A.updateIndex(0,4) 60 | expResult = "HEAD < [4]->(2) [2]->(3) [3]->(None) > TAIL" 61 | result = str(self.A) 62 | self.assertTrue(boolResult) 63 | self.assertEqual(result, expResult) 64 | print("\ntestUpdateIndex #1 PASSED!") 65 | 66 | boolResult = self.A.updateIndex(1,5) 67 | expResult = "HEAD < [4]->(5) [5]->(3) [3]->(None) > TAIL" 68 | result = str(self.A) 69 | self.assertTrue(boolResult) 70 | self.assertEqual(result, expResult) 71 | print("\ntestUpdateIndex #2 PASSED!") 72 | 73 | boolResult = self.A.updateIndex(2,6) 74 | expResult = "HEAD < [4]->(5) [5]->(6) [6]->(None) > TAIL" 75 | result = str(self.A) 76 | self.assertTrue(boolResult) 77 | self.assertEqual(result, expResult) 78 | print("\ntestUpdateIndex #3 PASSED!") 79 | 80 | boolResult = self.A.updateIndex(3,7) 81 | expResult = "HEAD < [4]->(5) [5]->(6) [6]->(None) > TAIL" 82 | result = str(self.A) 83 | self.assertFalse(boolResult) 84 | self.assertEqual(result, expResult) 85 | print("\ntestUpdateIndex #4 PASSED!") 86 | 87 | boolResult = self.A.updateIndex(-1,7) 88 | expResult = "HEAD < [4]->(5) [5]->(6) [6]->(None) > TAIL" 89 | result = str(self.A) 90 | self.assertFalse(boolResult) 91 | self.assertEqual(result, expResult) 92 | print("\ntestUpdateIndex #5 PASSED!") 93 | 94 | def testDeleteIndex(self): 95 | boolResult = self.A.deleteIndex(4) 96 | expResult = "HEAD < [1]->(2) [2]->(3) [3]->(None) > TAIL" 97 | result = str(self.A) 98 | self.assertFalse(boolResult) 99 | self.assertEqual(result, expResult) 100 | print("\ntestDeleteIndex #1 PASSED!") 101 | 102 | boolResult = self.A.deleteIndex(2) 103 | expResult = "HEAD < [1]->(2) [2]->(None) > TAIL" 104 | result = str(self.A) 105 | self.assertTrue(boolResult) 106 | self.assertEqual(result, expResult) 107 | print("\ntestDeleteIndex #2 PASSED!") 108 | 109 | boolResult = self.A.deleteIndex(-1) 110 | expResult = "HEAD < [1]->(2) [2]->(None) > TAIL" 111 | result = str(self.A) 112 | self.assertFalse(boolResult) 113 | self.assertEqual(result, expResult) 114 | print("\ntestDeleteIndex #3 PASSED!") 115 | 116 | boolResult = self.A.deleteIndex(0) 117 | expResult = "HEAD < [2]->(None) > TAIL" 118 | result = str(self.A) 119 | self.assertTrue(boolResult) 120 | self.assertEqual(result, expResult) 121 | print("\ntestDeleteIndex #4 PASSED!") 122 | 123 | boolResult = self.A.deleteIndex(0) 124 | expResult = "HEAD <> TAIL" 125 | result = str(self.A) 126 | self.assertTrue(boolResult) 127 | self.assertEqual(result, expResult) 128 | print("\ntestDeleteIndex #5 PASSED!") 129 | 130 | boolResult = self.A.deleteIndex(0) 131 | expResult = "HEAD <> TAIL" 132 | result = str(self.A) 133 | self.assertFalse(boolResult) 134 | self.assertEqual(result, expResult) 135 | print("\ntestDeleteIndex #6 PASSED!") 136 | 137 | def testInsertBeforeIndex(self): 138 | boolResult = self.A.insertBeforeIndex(-1,0) 139 | expResult = "HEAD < [1]->(2) [2]->(3) [3]->(None) > TAIL" 140 | result = str(self.A) 141 | self.assertFalse(boolResult) 142 | self.assertEqual(result, expResult) 143 | print("\ntestInsertBeforeIndex #1 PASSED!") 144 | 145 | boolResult = self.A.insertBeforeIndex(0,4) 146 | expResult = "HEAD < [4]->(1) [1]->(2) [2]->(3) [3]->(None) > TAIL" 147 | result = str(self.A) 148 | self.assertTrue(boolResult) 149 | self.assertEqual(result, expResult) 150 | print("\ntestInsertBeforeIndex #2 PASSED!") 151 | 152 | boolResult = self.A.insertBeforeIndex(3,5) 153 | expResult = "HEAD < [4]->(1) [1]->(2) [2]->(5) [5]->(3) [3]->(None) > TAIL" 154 | result = str(self.A) 155 | self.assertTrue(boolResult) 156 | self.assertEqual(result, expResult) 157 | print("\ntestInsertBeforeIndex #3 PASSED!") 158 | 159 | boolResult = self.A.insertBeforeIndex(5,6) 160 | expResult = "HEAD < [4]->(1) [1]->(2) [2]->(5) [5]->(3) [3]->(6) [6]->(None) > TAIL" 161 | result = str(self.A) 162 | self.assertTrue(boolResult) 163 | self.assertEqual(result, expResult) 164 | print("\ntestInsertBeforeIndex #4 PASSED!") 165 | 166 | boolResult = self.A.insertBeforeIndex(7,6) 167 | expResult = "HEAD < [4]->(1) [1]->(2) [2]->(5) [5]->(3) [3]->(6) [6]->(None) > TAIL" 168 | result = str(self.A) 169 | self.assertFalse(boolResult) 170 | self.assertEqual(result, expResult) 171 | print("\ntestInsertBeforeIndex #4 PASSED!") 172 | 173 | def testInsertAfterIndex(self): 174 | boolResult = self.A.insertAfterIndex(-2,0) 175 | expResult = "HEAD < [1]->(2) [2]->(3) [3]->(None) > TAIL" 176 | result = str(self.A) 177 | self.assertFalse(boolResult) 178 | self.assertEqual(result, expResult) 179 | print("\ntestInsertAfterIndex #1 PASSED!") 180 | 181 | boolResult = self.A.insertAfterIndex(-1,4) 182 | expResult = "HEAD < [4]->(1) [1]->(2) [2]->(3) [3]->(None) > TAIL" 183 | result = str(self.A) 184 | self.assertTrue(boolResult) 185 | self.assertEqual(result, expResult) 186 | print("\ntestInsertAfterIndex #2 PASSED!") 187 | 188 | boolResult = self.A.insertAfterIndex(2,5) 189 | expResult = "HEAD < [4]->(1) [1]->(2) [2]->(5) [5]->(3) [3]->(None) > TAIL" 190 | result = str(self.A) 191 | self.assertTrue(boolResult) 192 | self.assertEqual(result, expResult) 193 | print("\ntestInsertAfterIndex #3 PASSED!") 194 | 195 | boolResult = self.A.insertAfterIndex(4,6) 196 | expResult = "HEAD < [4]->(1) [1]->(2) [2]->(5) [5]->(3) [3]->(6) [6]->(None) > TAIL" 197 | result = str(self.A) 198 | self.assertTrue(boolResult) 199 | self.assertEqual(result, expResult) 200 | print("\ntestInsertAfterIndex #4 PASSED!") 201 | 202 | boolResult = self.A.insertAfterIndex(6,6) 203 | expResult = "HEAD < [4]->(1) [1]->(2) [2]->(5) [5]->(3) [3]->(6) [6]->(None) > TAIL" 204 | result = str(self.A) 205 | self.assertFalse(boolResult) 206 | self.assertEqual(result, expResult) 207 | print("\ntestInsertAfterIndex #5 PASSED!") 208 | 209 | def testDeleteData(self): 210 | boolResult = self.A.deleteData(4) 211 | expResult = "HEAD < [1]->(2) [2]->(3) [3]->(None) > TAIL" 212 | result = str(self.A) 213 | self.assertFalse(boolResult) 214 | self.assertEqual(result, expResult) 215 | print("\ntestDeleteData #1 PASSED!") 216 | 217 | boolResult = self.A.deleteData(3) 218 | expResult = "HEAD < [1]->(2) [2]->(None) > TAIL" 219 | result = str(self.A) 220 | self.assertTrue(boolResult) 221 | self.assertEqual(result, expResult) 222 | print("\ntestDeleteData #2 PASSED!") 223 | 224 | boolResult = self.A.deleteData(1) 225 | expResult = "HEAD < [2]->(None) > TAIL" 226 | result = str(self.A) 227 | self.assertTrue(boolResult) 228 | self.assertEqual(result, expResult) 229 | print("\ntestDeleteData #3 PASSED!") 230 | 231 | boolResult = self.A.deleteData(2) 232 | expResult = "HEAD <> TAIL" 233 | result = str(self.A) 234 | self.assertTrue(boolResult) 235 | self.assertEqual(result, expResult) 236 | print("\ntestDeleteData #4 PASSED!") 237 | 238 | boolResult = self.A.deleteData(2) 239 | expResult = "HEAD <> TAIL" 240 | result = str(self.A) 241 | self.assertFalse(boolResult) 242 | self.assertEqual(result, expResult) 243 | print("\ntestDeleteData #5 PASSED!") 244 | 245 | def testDeleteAllData(self): 246 | self.A.append(1) 247 | boolResult = self.A.deleteAllData(1) 248 | expResult = "HEAD < [2]->(3) [3]->(None) > TAIL" 249 | result = str(self.A) 250 | self.assertTrue(boolResult) 251 | self.assertEqual(result, expResult) 252 | print("\ntestDeleteAllData #1 PASSED!") 253 | 254 | boolResult = self.A.deleteAllData(1) 255 | expResult = "HEAD < [2]->(3) [3]->(None) > TAIL" 256 | result = str(self.A) 257 | self.assertFalse(boolResult) 258 | self.assertEqual(result, expResult) 259 | print("\ntestDeleteAllData #2 PASSED!") 260 | 261 | def testDeleteList(self): 262 | self.A.deleteList() 263 | expResult = "HEAD <> TAIL" 264 | result = str(self.A) 265 | self.assertEqual(result, expResult) 266 | print("\ntestDeleteList PASSED!") 267 | 268 | def testInsertAfterEveryData(self): 269 | self.A.append(1) 270 | boolResult = self.A.insertAfterEveryData(1,4) 271 | expResult = "HEAD < [1]->(4) [4]->(2) [2]->(3) [3]->(1) [1]->(4) [4]->(None) > TAIL" 272 | result = str(self.A) 273 | self.assertTrue(boolResult) 274 | self.assertEqual(result, expResult) 275 | print("\ntestInsertAfterEveryData #1 PASSED!") 276 | 277 | boolResult = self.A.insertAfterEveryData(0,5) 278 | expResult = "HEAD < [1]->(4) [4]->(2) [2]->(3) [3]->(1) [1]->(4) [4]->(None) > TAIL" 279 | result = str(self.A) 280 | self.assertFalse(boolResult) 281 | self.assertEqual(result, expResult) 282 | print("\ntestInsertAfterEveryData #2 PASSED!") 283 | 284 | def testInsertBeforeEveryData(self): 285 | self.A.append(1) 286 | boolResult = self.A.insertBeforeEveryData(1,4) 287 | expResult = "HEAD < [4]->(1) [1]->(2) [2]->(3) [3]->(4) [4]->(1) [1]->(None) > TAIL" 288 | result = str(self.A) 289 | self.assertTrue(boolResult) 290 | self.assertEqual(result, expResult) 291 | print("\ntestInsertBeforeEveryData #1 PASSED!") 292 | 293 | boolResult = self.A.insertBeforeEveryData(0,5) 294 | expResult = "HEAD < [4]->(1) [1]->(2) [2]->(3) [3]->(4) [4]->(1) [1]->(None) > TAIL" 295 | result = str(self.A) 296 | self.assertFalse(boolResult) 297 | self.assertEqual(result, expResult) 298 | print("\ntestInsertBeforeEveryData #2 PASSED!") 299 | 300 | def testCopyList(self): 301 | B = LinkedList() 302 | B = self.A.copyList() 303 | 304 | self.A.append(4) 305 | B.append(5) 306 | 307 | expAResult = "HEAD < [1]->(2) [2]->(3) [3]->(4) [4]->(None) > TAIL" 308 | expBResult = "HEAD < [1]->(2) [2]->(3) [3]->(5) [5]->(None) > TAIL" 309 | Aresult = str(self.A) 310 | Bresult = str(B) 311 | 312 | self.assertEqual(expAResult, Aresult) 313 | self.assertEqual(expBResult, Bresult) 314 | self.assertNotEqual(Aresult,Bresult) 315 | print("\ntestCopyList PASSED!") 316 | 317 | def testFindMthToLastNode(self): 318 | expResult = None 319 | result = self.A.findMthToLastNode(-1) 320 | self.assertEqual(result,expResult) 321 | print("\ntestFindMthToLastNode #1 PASSED!") 322 | 323 | expResult = None 324 | result = self.A.findMthToLastNode(0) 325 | self.assertEqual(result,expResult) 326 | print("\ntestFindMthToLastNode #2 PASSED!") 327 | 328 | expResult = 3 329 | result = self.A.findMthToLastNode(1) 330 | self.assertEqual(result,expResult) 331 | print("\ntestFindMthToLastNode #3 PASSED!") 332 | 333 | expResult = 2 334 | result = self.A.findMthToLastNode(2) 335 | self.assertEqual(result,expResult) 336 | print("\ntestFindMthToLastNode #4 PASSED!") 337 | 338 | expResult = 1 339 | result = self.A.findMthToLastNode(3) 340 | self.assertEqual(result,expResult) 341 | print("\ntestFindMthToLastNode #5 PASSED!") 342 | 343 | expResult = None 344 | result = self.A.findMthToLastNode(4) 345 | self.assertEqual(result,expResult) 346 | print("\ntestFindMthToLastNode #6 PASSED!") 347 | 348 | if __name__ == '__main__': 349 | unittest.main() -------------------------------------------------------------------------------- /LinkedLists/README.md: -------------------------------------------------------------------------------- 1 | # *Linked Lists:* 2 | ## *Operations:* 3 | - insert 4 | - append 5 | - returnIndex 6 | - updateIndex 7 | - deleteIndex 8 | - insertBeforeIndex 9 | - insertAfterIndex 10 | - deleteData 11 | - deleteAllData 12 | - insertAfterEveryData 13 | - insertBeforeEveryData 14 | - deleteList 15 | - copyList 16 | - findMthToLastNode 17 | 18 | ## *Types:* 19 | - Single LL with head pointer 20 | - Double LL with head pointer 21 | - Circular LL with head & tail pointers 22 | 23 | Unit Tests to test all 3 types and each operation 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Python Data Structures 2 | ====================== 3 | ### Lorem_ipsum.txt included for testing and timing purposes. 4 | ### Currently used to test Tries and Hash Table 5 | 6 | ## *ADTS:* 7 | - Queue with head and tail ptr, insert new at head, remove old at tail 8 | - Queue with only head ptr, remove old at head, append new to the end 9 | - Stack (push/pop at head) 10 | - Priority Queue (uses an array-based Binary Heap) 11 | 12 | ## *Linked List Operations:* 13 | - insert 14 | - append 15 | - returnIndex 16 | - updateIndex 17 | - deleteIndex 18 | - insertBeforeIndex 19 | - insertAfterIndex 20 | - deleteData 21 | - deleteAllData 22 | - insertAfterEveryData 23 | - insertBeforeEveryData 24 | - deleteList 25 | - copyList 26 | - findMthToLastNode 27 | 28 | ### *Types:* 29 | - Single LL with head pointer 30 | - Double LL with head pointer 31 | - Circular LL with head & tail pointers 32 | 33 | Unit Tests to test all 3 types and each operation 34 | 35 | ## *Binary Search Tree Operations:* 36 | - insert 37 | - insertList 38 | - find 39 | - delete 40 | - traverseBFS 41 | - traverseDFSpreorder 42 | - traverseDFSinorder 43 | - traverseDFSpostorder 44 | - copyTree 45 | - findMin 46 | - findMax 47 | 48 | ### *Types:* 49 | - Iterative (uses Queue(head ptr) and Stack for traversals) 50 | - Recursive (inherits from iterative approach, reimplements insert,find,delete,DFS,findMin,findMax) 51 | 52 | Unit Tests to test each operation for both types 53 | 54 | ## *AVL Tree Operations:* 55 | - insert (Balance Factor Calculations added) 56 | - delete (Balance Factor Calculations added) 57 | - deleteTree (new, none of the other trees has this added at this time) 58 | - checkBalance (check the Balance Factor to see if a rotation(s) is necessary) 59 | - calcBF (recalculate the BF for the the given root and all ancestors if necessary, insert version and delete version) 60 | - rotateLeft 61 | - rotateRight 62 | 63 | - All redefined operations are recursive. 64 | 65 | ### *Rest of the operations are inherited from the recursive BST* 66 | 67 | Unit Tests to test each operation and valid rotations. 68 | 69 | ## *Red-Black Tree Operations:* 70 | - insert (Color Check added) 71 | - delete (Color Check added) 72 | - deleteTree (Same as AVL) 73 | - checkColor (determines the new coloring and if any rotations are needed - version for post-insert and post-delete) 74 | - rotateLeft (Same as AVL) 75 | - rotateRight (Same as AVL) 76 | 77 | - All redefined operations are recursive. 78 | 79 | ### *Rest of the operations are inherited from the recursive BST* 80 | 81 | Unit Tests to test each operation, valid rotations and correct coloring. 82 | 83 | ## *Splay Tree Operations:* 84 | - insert (splaying added) 85 | - find (splaying added for valid/invalid finds) 86 | - delete (splaying added for valid/invalid deletes) 87 | - copyTree (redefined due to the structure of the splay tree varying based off order of inserts) 88 | - findRecentAccessed (returns the root, only useful for a splay tree) 89 | - splay (rotates the tree so that the most recent inserted/found node or parent of a recent delete is rotated to the root) 90 | 91 | - All redefined operations are recursive. 92 | 93 | ### *Rest of the operations are inherited from the recursive BST* 94 | 95 | Unit Tests to test each operation and valid splaying. 96 | 97 | ## *Binary Heap Operations:* 98 | - traverseBFS 99 | - insert (with heapifyUp to ensure heap property) 100 | - insertList 101 | - delete (with heapifyDown to ensure heap property) 102 | - merge (2 heaps -> 1 heap) 103 | - peek (get max value) 104 | - copyHeap 105 | 106 | ### *Types:* 107 | - Tree Structure (uses ptrs) 108 | - Array Structure (no ptrs needed) 109 | 110 | Units Tests to test each operation and to ensure proper tracking 111 | of next insert/delete location to ensure shape property 112 | 113 | ## *Trie Operations:* 114 | - traverse(Words|Prefixes) - Outputs words for generic type or all prefixes for prefix count versions 115 | - traverseBFS 116 | - add 117 | - remove 118 | - isMember (full words or prefixes specifically added) 119 | - updateValue (Generic type only) 120 | - getValue 121 | 122 | ### *Types:* 123 | - Generic - allows adding words with a corresponding value, all prefix node values are None 124 | - Prefix Count - user only adds words, values correspond to number of times that prefix is used 125 | - Prefix Count Speed - Same as above, but using more space to allow for faster indexing 126 | 127 | Unit tests to test each operation for all 3 types 128 | 129 | ## *Sorting:* 130 | ### Selection Sorts: 131 | - HeapSort - uses an array-based binary heap, in-place sort, not stable, 132 | O(n) best case, O(n log n) AVG/worst case performance, O(1) auxiliary space 133 | 134 | ### Merge Sorts: 135 | - MergeSort - not in place, stable sort, O(n log n) best/AVG/worst case performance, 136 | O(n) auxiliary space 137 | 138 | ### Exchange Sorts: 139 | - QuickSort - not in place, not stable, O(n log n) best/AVG, O(n^2) worst case 140 | performance, O(n) auxiliary space, fastest on average 141 | 142 | Tested using language provided sort method to compare the result on a random.shuffle() list 143 | 144 | ## *Hash Table Operations:* 145 | - add 146 | - updateValue 147 | - delete 148 | - lookUp 149 | - hash 150 | 151 | ### *Types:* 152 | - Separate Chaining Collision resolution 153 | 154 | Unit tests to test each operation 155 | 156 | ## *Graphs:* 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 |
TypeStorageAdd VertexAdd EdgeRemove VertexRemove EdgeQuery
Adjacency ListO(|V|+|E|)O(1)O(1)O(|E|)O(|E|)O(|V|)
Adjacency MatrixO(|V|^2)O(|V|^2)O(1)O(|V|^2)O(1)O(1)
Incidence ListO(|V|+|E|)O(1)O(1)O(|E|)O(|E|)O(|E|)
Incidence MatrixO(|V|*|E|)O(|V|*|E|)O(|V|*|E|)O(|V|*|E|)O(|V|*|E|)O(|E|)
175 | 176 | ### *Adjacency List:* 177 | - Vertices are stored in a dictionary. Each vertex has a list of neighboring vertices. 178 | - Supports direct and undirected graphs. 179 | 180 | *Operations:* 181 | - addVertex 182 | - addEdge 183 | - removeVertex 184 | - removeEdge 185 | - copyGraph 186 | 187 | *Algorithm:* 188 | *Breadth First Search* 189 | - traverseBFS 190 | - shortestPath 191 | 192 | *Depth First Search* 193 | - DAG test 194 | - traverseDFS 195 | - topological sort 196 | - find strongly connnected components 197 | - compute tranpose - used to find strongly connnected components 198 | - Classification of edges into: 199 | 1)Tree Edges 200 | 2)Back Edges 201 | 3)Forward/Cross Edges 202 | 203 | ### *Adjacency Matrix:* 204 | - Matrix is V rows and V columns. If a vertex V1 is adjacent to vertex V2, then the V1 row and V2 column entry in the matrix will be True or carry a weight (if weighted graph) else False or infinite weight. 205 | - If the graph is undirected the matrix will equal it's own transpose 206 | 207 | *Operations:* 208 | - addVertex 209 | - addEdge 210 | - removeVertex 211 | - removeEdge 212 | 213 | *Algorithm:* 214 | *Breadth First Search* 215 | - traverseBFS 216 | - shortestPath 217 | 218 | *Depth First Search* 219 | - traverseDFS 220 | - Classification of edges into: 221 | 1)Tree Edges 222 | 2)Back Edges 223 | 3)Forward/Cross Edges 224 | 225 | ### *Incidence List:* 226 | - Not Implemented 227 | 228 | ### *Incidence Matrix:* 229 | - Not Implemented 230 | 231 | -------------------------------------------------------------------------------- /Sorting/BubbleSort.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 4/8/2013 4 | 5 | #Simple BubbleSort implementation 6 | # Stable sort, preserve order of equal elements 7 | # In-place sort 8 | 9 | # O(n^2) - worst/AVG case 10 | # O(n) - best case (already sorted list) 11 | # O(1) auxilary - worst case space complexity 12 | 13 | import random 14 | 15 | def BubbleSort(unsortedList): 16 | if len(unsortedList) < 2: 17 | swap = False 18 | else: 19 | swap = True 20 | while swap: 21 | swap = False 22 | for index in range(0,len(unsortedList)-1): 23 | if unsortedList[index] > unsortedList[index+1]: 24 | temp = unsortedList[index] 25 | unsortedList[index] = unsortedList[index+1] 26 | unsortedList[index+1] = temp 27 | swap = True 28 | return unsortedList 29 | 30 | if __name__ == '__main__': 31 | empty = [] 32 | print("Empty Result: %s\n"%(BubbleSort(empty))) 33 | one = [1] 34 | print("One Element Result: %s\n"%(BubbleSort(one))) 35 | two = [2,1] 36 | print("Two Element Result: %s\n"%(BubbleSort(two))) 37 | three = [2,3,1] 38 | print("Three Element Result: %s\n"%(BubbleSort(three))) 39 | 40 | #Positives Only 41 | unsortedList = [x for x in range(0,101)] 42 | random.shuffle(unsortedList) 43 | 44 | print("UnsortedList: %s\n"%unsortedList) 45 | sortedList = BubbleSort(unsortedList) 46 | print("BubbleSort Returned: %s\n"%sortedList) 47 | 48 | unsortedList.sort() 49 | print("Using list.sort() returned: %s\n"%unsortedList) 50 | 51 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) 52 | 53 | #Negatives Only 54 | unsortedList = [x for x in range(-100,0)] 55 | random.shuffle(unsortedList) 56 | 57 | print("UnsortedList: %s\n"%unsortedList) 58 | sortedList = BubbleSort(unsortedList) 59 | print("BubbleSort Returned: %s\n"%sortedList) 60 | 61 | unsortedList.sort() 62 | print("Using list.sort() returned: %s\n"%unsortedList) 63 | 64 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) 65 | 66 | #Positives and Negatives 67 | unsortedList = [x for x in range(-100,101)] 68 | random.shuffle(unsortedList) 69 | 70 | print("UnsortedList: %s\n"%unsortedList) 71 | sortedList = BubbleSort(unsortedList) 72 | print("BubbleSort Returned: %s\n"%sortedList) 73 | 74 | unsortedList.sort() 75 | print("Using list.sort() returned: %s\n"%unsortedList) 76 | 77 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) -------------------------------------------------------------------------------- /Sorting/HeapSort.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/25/2013 4 | 5 | # Similar to Binary_Heap_Array_Structure.py but this includes a sorting mechanic 6 | # O(n) best case performance 7 | # O(n log n) AVG/worst case performance 8 | # O(n log n) to build heap + O(n log n) to swap each max value and heapify 9 | # O(1) - auxiliary space 10 | # Not a stable sort 11 | # In-place sort 12 | 13 | import random 14 | 15 | class HeapSort: 16 | def __init__(self, unsortedList): 17 | self.nodes = [] 18 | self.insertList(unsortedList) 19 | self.index = 1 20 | 21 | def __str__(self): 22 | return str(self.nodes) 23 | 24 | def getSorted(self): 25 | maxValue = self.delete() 26 | while self.index < len(self.nodes)-1: 27 | self.index += 1 28 | maxValue = self.delete() 29 | return self.nodes 30 | 31 | def insert(self,key): 32 | self.nodes.append(key) 33 | self.heapifyUp() 34 | return True 35 | 36 | def insertList(self, alist): 37 | boolResult = True 38 | for item in alist: 39 | if(self.insert(item) == False): 40 | boolResult = False 41 | return boolResult 42 | 43 | def delete(self): 44 | if self.isEmpty(): 45 | return None 46 | returnValue = self.nodes[0] 47 | #Swap the first and last available nodes (self.index increments after each delete) 48 | self.nodes[0] = self.nodes[-self.index] 49 | self.nodes[-self.index] = returnValue 50 | self.heapifyDown(0, self.getLeftChildIndex(0), self.getRightChildIndex(0)) 51 | return returnValue 52 | 53 | def heapifyUp(self): 54 | child = len(self.nodes)-1 55 | parent = self.getParentIndex(child) 56 | while(self.nodes[child] > self.nodes[parent]): 57 | temp = self.nodes[child] 58 | self.nodes[child] = self.nodes[parent] 59 | self.nodes[parent] = temp 60 | child = parent 61 | parent = self.getParentIndex(child) 62 | 63 | def heapifyDown(self,parent,left,right): 64 | if not self.validChild(left) and not self.validChild(right): 65 | return 66 | if not self.validChild(right) or self.nodes[left] > self.nodes[right]: 67 | if(self.nodes[left] > self.nodes[parent]): 68 | temp = self.nodes[parent] 69 | self.nodes[parent] = self.nodes[left] 70 | self.nodes[left] = temp 71 | parent = self.getLeftChildIndex(parent) 72 | else: 73 | return 74 | else: 75 | if(self.nodes[right] > self.nodes[parent]): 76 | temp = self.nodes[parent] 77 | self.nodes[parent] = self.nodes[right] 78 | self.nodes[right] = temp 79 | parent = self.getRightChildIndex(parent) 80 | else: 81 | return 82 | self.heapifyDown(parent, self.getLeftChildIndex(parent), self.getRightChildIndex(parent)) 83 | 84 | def validChild(self,index): 85 | return True if index < len(self.nodes)-self.index else False 86 | 87 | def getLeftChildIndex(self,index): 88 | return ((2*index)+1) 89 | 90 | def getLeftChild(self,index): 91 | child = self.getLeftChildIndex(index) 92 | return self.nodes[child] if self.validChild(child) else None 93 | 94 | def getRightChildIndex(self,index): 95 | return ((2*index)+2) 96 | 97 | def getRightChild(self,index): 98 | child = self.getRightChildIndex(index) 99 | return self.nodes[child] if self.validChild(child) else None 100 | 101 | def getParentIndex(self,index): 102 | return int((index-1)/2) 103 | 104 | def getParent(self,index): 105 | return self.nodes[self.getParentIndex(index)] if index > 0 else None 106 | 107 | def isEmpty(self): 108 | return len(self.nodes)==0 109 | 110 | if __name__ == '__main__': 111 | 112 | empty = [] 113 | emptyHeap = HeapSort(empty) 114 | print("Empty Result: %s\n"%(emptyHeap.getSorted())) 115 | 116 | one = [1] 117 | oneHeap = HeapSort(one) 118 | print("One Element Result: %s\n"%(oneHeap.getSorted())) 119 | 120 | two = [2,1] 121 | twoHeap = HeapSort(two) 122 | print("Two Element Result: %s\n"%(twoHeap.getSorted())) 123 | 124 | three = [2,3,1] 125 | threeHeap = HeapSort(three) 126 | print("Three Element Result: %s\n"%(threeHeap.getSorted())) 127 | 128 | a = [x for x in range(-100,101)] 129 | random.shuffle(a) 130 | 131 | print("Shuffled List: %s\n"%a) 132 | 133 | heap = HeapSort(a) 134 | sortedList = heap.getSorted() 135 | a.sort() 136 | 137 | print("Heap Sorted: %s\n" % sortedList) 138 | print("List Sorted: %s\n" % a) 139 | print("Sorted %s"%(sortedList == a)) -------------------------------------------------------------------------------- /Sorting/InsertionSort.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 4/8/2013 4 | 5 | # Insertion Sort implementation 6 | # Stable sort, preserve order of equal elements 7 | # In-place sort 8 | # Efficient for small data sets 9 | 10 | # O(n^2) - worst/AVG case 11 | # O(n) - best case (already sorted list) 12 | # O(1) auxilary - worst case space complexity 13 | 14 | import random 15 | 16 | def InsertionSort(unsortedList): 17 | if len(unsortedList) < 2: 18 | return unsortedList 19 | for index in range(1,len(unsortedList)): 20 | while unsortedList[index] < unsortedList[index-1]: 21 | temp = unsortedList[index] 22 | unsortedList[index] = unsortedList[index-1] 23 | unsortedList[index-1] = temp 24 | if index > 1: 25 | index -= 1 26 | return unsortedList 27 | 28 | if __name__ == '__main__': 29 | empty = [] 30 | print("Empty Result: %s\n"%(InsertionSort(empty))) 31 | one = [1] 32 | print("One Element Result: %s\n"%(InsertionSort(one))) 33 | two = [2,1] 34 | print("Two Element Result: %s\n"%(InsertionSort(two))) 35 | three = [2,3,1] 36 | print("Three Element Result: %s\n"%(InsertionSort(three))) 37 | 38 | #Positives Only 39 | unsortedList = [x for x in range(0,101)] 40 | random.shuffle(unsortedList) 41 | 42 | print("UnsortedList: %s\n"%unsortedList) 43 | sortedList = InsertionSort(unsortedList) 44 | print("InsertionSort Returned: %s\n"%sortedList) 45 | 46 | unsortedList.sort() 47 | print("Using list.sort() returned: %s\n"%unsortedList) 48 | 49 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) 50 | 51 | #Negatives Only 52 | unsortedList = [x for x in range(-100,0)] 53 | random.shuffle(unsortedList) 54 | 55 | print("UnsortedList: %s\n"%unsortedList) 56 | sortedList = InsertionSort(unsortedList) 57 | print("InsertionSort Returned: %s\n"%sortedList) 58 | 59 | unsortedList.sort() 60 | print("Using list.sort() returned: %s\n"%unsortedList) 61 | 62 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) 63 | 64 | #Positives and Negatives 65 | unsortedList = [x for x in range(-100,101)] 66 | random.shuffle(unsortedList) 67 | 68 | print("UnsortedList: %s\n"%unsortedList) 69 | sortedList = InsertionSort(unsortedList) 70 | print("InsertionSort Returned: %s\n"%sortedList) 71 | 72 | unsortedList.sort() 73 | print("Using list.sort() returned: %s\n"%unsortedList) 74 | 75 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) -------------------------------------------------------------------------------- /Sorting/MergeSort.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/26/2013 4 | 5 | # O(n log n) best/AVG/worst running time to sort. 6 | # O(n) auxiliary space 7 | # Stable sort, preserve order of equal elements 8 | # Not in-place 9 | # More efficient at handling slow-to-access sequential media 10 | # Good for sorting a Linked List 11 | 12 | # Divide the unsorted list into n sublists, each containing 1 element 13 | # Repeatedly merge sublists to produce new sublists until there is only 1 sublist 14 | # remaining. This will be the sorted list. 15 | 16 | import random 17 | 18 | def MergeSort(unsortedList): 19 | if len(unsortedList) <= 1: 20 | return unsortedList 21 | 22 | left = [] 23 | right = [] 24 | 25 | left = unsortedList[0:int(len(unsortedList)/2)] 26 | right = unsortedList[int(len(unsortedList)/2):] 27 | 28 | left = MergeSort(left) 29 | right = MergeSort(right) 30 | 31 | return Merge(left,right) 32 | 33 | def Merge(left, right): 34 | result = [] 35 | 36 | while len(left) > 0 or len(right) > 0: 37 | if len(left) == 0: 38 | for data in right: 39 | result.append(data) 40 | break 41 | elif len(right) == 0: 42 | for data in left: 43 | result.append(data) 44 | break 45 | else: 46 | if right[0] < left[0]: 47 | result.append(right[0]) 48 | right = right[1:] 49 | else: 50 | result.append(left[0]) 51 | left = left[1:] 52 | return result 53 | 54 | if __name__ == '__main__': 55 | empty = [] 56 | print("Empty Result: %s\n"%(MergeSort(empty))) 57 | one = [1] 58 | print("One Element Result: %s\n"%(MergeSort(one))) 59 | two = [2,1] 60 | print("Two Element Result: %s\n"%(MergeSort(two))) 61 | three = [2,3,1] 62 | print("Three Element Result: %s\n"%(MergeSort(three))) 63 | 64 | #Positives Only 65 | unsortedList = [x for x in range(0,101)] 66 | random.shuffle(unsortedList) 67 | 68 | print("UnsortedList: %s\n"%unsortedList) 69 | sortedList = MergeSort(unsortedList) 70 | print("MergeSort Returned: %s\n"%sortedList) 71 | 72 | unsortedList.sort() 73 | print("Using list.sort() returned: %s\n"%unsortedList) 74 | 75 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) 76 | 77 | #Negatives Only 78 | unsortedList = [x for x in range(-100,0)] 79 | random.shuffle(unsortedList) 80 | 81 | print("UnsortedList: %s\n"%unsortedList) 82 | sortedList = MergeSort(unsortedList) 83 | print("MergeSort Returned: %s\n"%sortedList) 84 | 85 | unsortedList.sort() 86 | print("Using list.sort() returned: %s\n"%unsortedList) 87 | 88 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) 89 | 90 | #Positives and Negatives 91 | unsortedList = [x for x in range(-100,101)] 92 | random.shuffle(unsortedList) 93 | 94 | print("UnsortedList: %s\n"%unsortedList) 95 | sortedList = MergeSort(unsortedList) 96 | print("MergeSort Returned: %s\n"%sortedList) 97 | 98 | unsortedList.sort() 99 | print("Using list.sort() returned: %s\n"%unsortedList) 100 | 101 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) -------------------------------------------------------------------------------- /Sorting/QuickSort.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/26/2013 4 | 5 | # O(n log n) best/AVG case performance 6 | # O(n^2) worst case performance - already sorted array using left-most element as pivot 7 | # O(n) auxiliary space 8 | # Not a stable sort 9 | # Not in Place 10 | # This implementation uses the middle index as the pivot 11 | 12 | # Pick an element, called a pivot, from the list. 13 | # Reorder the list so that all elements with values less than the pivot come 14 | # before the pivot, while all elements with values greater than the pivot 15 | # come after it 16 | # Recursively sort the sub-list of elements with smaller values and 17 | # separately the sub-list of elements with greater values. 18 | 19 | import random 20 | 21 | def QuickSort(unsortedList): 22 | if len(unsortedList) <= 1: 23 | return unsortedList 24 | 25 | pivot = unsortedList[int(len(unsortedList)/2)] 26 | unsortedList = unsortedList[0:int(len(unsortedList)/2)] + unsortedList[int(len(unsortedList)/2)+1:] 27 | less = [] 28 | greater = [] 29 | for x in unsortedList: 30 | if x <= pivot: 31 | less.append(x) 32 | else: 33 | greater.append(x) 34 | return QuickSort(less) + [pivot] + QuickSort(greater) 35 | 36 | if __name__ == '__main__': 37 | empty = [] 38 | print("Empty Result: %s\n"%(QuickSort(empty))) 39 | one = [1] 40 | print("One Element Result: %s\n"%(QuickSort(one))) 41 | two = [2,1] 42 | print("Two Element Result: %s\n"%(QuickSort(two))) 43 | three = [2,3,1] 44 | print("Three Element Result: %s\n"%(QuickSort(three))) 45 | 46 | #Positives Only 47 | unsortedList = [x for x in range(0,101)] 48 | random.shuffle(unsortedList) 49 | 50 | print("UnsortedList: %s\n"%unsortedList) 51 | sortedList = QuickSort(unsortedList) 52 | print("QuickSort Returned: %s\n"%sortedList) 53 | 54 | unsortedList.sort() 55 | print("Using list.sort() returned: %s\n"%unsortedList) 56 | 57 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) 58 | 59 | #Negatives Only 60 | unsortedList = [x for x in range(-100,0)] 61 | random.shuffle(unsortedList) 62 | 63 | print("UnsortedList: %s\n"%unsortedList) 64 | sortedList = QuickSort(unsortedList) 65 | print("QuickSort Returned: %s\n"%sortedList) 66 | 67 | unsortedList.sort() 68 | print("Using list.sort() returned: %s\n"%unsortedList) 69 | 70 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) 71 | 72 | #Positives and Negatives 73 | unsortedList = [x for x in range(-100,101)] 74 | random.shuffle(unsortedList) 75 | 76 | print("UnsortedList: %s\n"%unsortedList) 77 | sortedList = QuickSort(unsortedList) 78 | print("QuickSort Returned: %s\n"%sortedList) 79 | 80 | unsortedList.sort() 81 | print("Using list.sort() returned: %s\n"%unsortedList) 82 | 83 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) -------------------------------------------------------------------------------- /Sorting/README.md: -------------------------------------------------------------------------------- 1 | # *Sorting:* 2 | ## Selection Sorts: 3 | ### HeapSort: 4 | - uses an array-based binary heap 5 | - in-place sort, not stable 6 | - O(n) best case, O(n log n) AVG/worst case performance 7 | - O(1) auxiliary space 8 | 9 | ### Selection Sort: 10 | - stable, in-place 11 | - O(n^2) best/AVG/worst case performance 12 | - O(1) auxiliary space 13 | 14 | ## Merge Sorts: 15 | ### MergeSort: 16 | - not in place, stable sort 17 | - O(n log n) best/AVG/worst case performance 18 | - O(n) auxiliary space 19 | 20 | ## Exchange Sorts: 21 | ### QuickSort: 22 | - not in place, not stable 23 | - O(n log n) best/AVG, O(n^2) worst case performance 24 | - O(n) auxiliary space 25 | - fastest on average 26 | 27 | ### BubbleSort: 28 | - stable, in-place 29 | - O(n^2) - worst/AVG case, O(n) - best case (already sorted list) 30 | - O(1) auxilary - worst case space complexity 31 | 32 | ## Insertion Sorts: 33 | ### Insertion Sort: 34 | - stable, in-place 35 | - O(n^2) - worst/AVG case, O(n) - best case (already sorted list) 36 | - O(1) auxilary - worst case space complexity 37 | 38 | All tested using language provided sort method to compare the result on a random.shuffle() list 39 | -------------------------------------------------------------------------------- /Sorting/SelectionSort.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 4/9/2013 4 | 5 | # Selection Sort implementation 6 | # Stable sort, preserve order of equal elements 7 | # In-place sort 8 | # Efficient for small data sets 9 | 10 | # O(n^2) - worst/AVG/best case 11 | # O(1) auxilary - worst case space complexity 12 | 13 | import random 14 | 15 | def SelectionSort(unsortedList): 16 | if len(unsortedList) < 2: 17 | return unsortedList 18 | for index in range(0,len(unsortedList)-1): 19 | minValue = float('inf') 20 | swapIndex = None 21 | for current in range(index,len(unsortedList)): 22 | if unsortedList[current] < minValue: 23 | minValue = unsortedList[current] 24 | swapIndex = current 25 | temp = unsortedList[index] 26 | unsortedList[index] = minValue 27 | unsortedList[swapIndex] = temp 28 | return unsortedList 29 | 30 | if __name__ == '__main__': 31 | empty = [] 32 | print("Empty Result: %s\n"%(SelectionSort(empty))) 33 | one = [1] 34 | print("One Element Result: %s\n"%(SelectionSort(one))) 35 | two = [2,1] 36 | print("Two Element Result: %s\n"%(SelectionSort(two))) 37 | three = [2,3,1] 38 | print("Three Element Result: %s\n"%(SelectionSort(three))) 39 | 40 | #Positives Only 41 | unsortedList = [x for x in range(0,101)] 42 | random.shuffle(unsortedList) 43 | 44 | print("UnsortedList: %s\n"%unsortedList) 45 | sortedList = SelectionSort(unsortedList) 46 | print("SelectionSort Returned: %s\n"%sortedList) 47 | 48 | unsortedList.sort() 49 | print("Using list.sort() returned: %s\n"%unsortedList) 50 | 51 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) 52 | 53 | #Negatives Only 54 | unsortedList = [x for x in range(-100,0)] 55 | random.shuffle(unsortedList) 56 | 57 | print("UnsortedList: %s\n"%unsortedList) 58 | sortedList = SelectionSort(unsortedList) 59 | print("SelectionSort Returned: %s\n"%sortedList) 60 | 61 | unsortedList.sort() 62 | print("Using list.sort() returned: %s\n"%unsortedList) 63 | 64 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) 65 | 66 | #Positives and Negatives 67 | unsortedList = [x for x in range(-100,101)] 68 | random.shuffle(unsortedList) 69 | 70 | print("UnsortedList: %s\n"%unsortedList) 71 | sortedList = SelectionSort(unsortedList) 72 | print("SelectionSort Returned: %s\n"%sortedList) 73 | 74 | unsortedList.sort() 75 | print("Using list.sort() returned: %s\n"%unsortedList) 76 | 77 | print("Sorted?: %s\n\n"%(unsortedList==sortedList)) -------------------------------------------------------------------------------- /Sorting/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirob2005/Python_Data_Structures/2851dc124e9b52391842521e584bf5ce716f3740/Sorting/__init__.py -------------------------------------------------------------------------------- /Trees/ADTs/Queue_head.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/18/2013 4 | 5 | # Typical Queue. Only has head ptr. New items go to the end. 6 | # Returned values come from the head. 7 | 8 | class Element: 9 | def __init__(self, data, next): 10 | self.data = data 11 | self.next = next 12 | 13 | class Queue: 14 | def __init__(self): 15 | self.head = None 16 | 17 | def __str__(self): 18 | ptr = self.head 19 | if(self.head==None): 20 | string = "Front < > Back" 21 | else: 22 | string = "Front < " 23 | while ptr: 24 | string += ("%s "%ptr.data) 25 | ptr = ptr.next 26 | string += "> Back" 27 | return string 28 | 29 | def enQueue(self,data): 30 | #Append the most recent node to the end 31 | ptr = self.head 32 | if(ptr == None): 33 | self.head = Element(data,self.head) 34 | else: 35 | while ptr.next: 36 | ptr=ptr.next 37 | ptr.next = Element(data, None) 38 | 39 | def deQueue(self): 40 | #move head ptr and return previous head 41 | if(self.head == None): 42 | return None 43 | ptr = self.head 44 | self.head = self.head.next 45 | ptr.next = None 46 | return ptr.data 47 | 48 | if __name__ == '__main__': 49 | myQ = Queue() 50 | 51 | for data in [1,2,3,4,5]: 52 | myQ.enQueue(data) 53 | 54 | print(myQ) 55 | 56 | for key in ['First','Second','Third','Fourth','Fifth']: 57 | print("%s element out: %s" % (key,myQ.deQueue())) 58 | print (myQ) 59 | 60 | print("Test Empty: %s"%myQ.deQueue()) 61 | print (myQ) 62 | 63 | print("_______") 64 | for data in [1,2,3,4]: 65 | print("Adding %s" % data) 66 | myQ.enQueue(data) 67 | print(myQ) 68 | print("Adding %s" % data) 69 | myQ.enQueue(data) 70 | print(myQ) 71 | print("Removing %s"%myQ.deQueue()) 72 | print(myQ) 73 | 74 | print(myQ) 75 | print("_______") 76 | 77 | first = myQ.deQueue() 78 | while first != None: 79 | print("Removing %s"% first) 80 | print(myQ) 81 | first = myQ.deQueue() -------------------------------------------------------------------------------- /Trees/ADTs/Queue_modified_for_heap_use.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/23/2013 4 | 5 | # This Queue also features the ability to delete the last thing added to the 6 | # queue and insert an item in front of the Queue to be used in Binary_Heap.py 7 | # to keep track of the upcoming node's parents as described in Binary_Heap.py. 8 | 9 | class Element: 10 | def __init__(self, data, next): 11 | self.data = data 12 | self.next = next 13 | 14 | class Queue: 15 | def __init__(self): 16 | self.head = None 17 | 18 | def __str__(self): 19 | ptr = self.head 20 | if(self.head==None): 21 | string = "Front < > Back" 22 | else: 23 | string = "Front < " 24 | while ptr: 25 | string += ("%s "%ptr.data) 26 | ptr = ptr.next 27 | string += "> Back" 28 | return string 29 | 30 | def insert(self,data): 31 | #Insert in Front of Queue 32 | self.head = Element(data,self.head) 33 | 34 | def getLast(self): 35 | if(not self.head): 36 | return None 37 | ptr = self.head 38 | if(ptr.next): 39 | while ptr.next.next: 40 | ptr = ptr.next 41 | returnValue = ptr.next.data 42 | ptr.next = None 43 | else: 44 | returnValue = ptr.data 45 | self.head = None 46 | return returnValue 47 | 48 | 49 | def enQueue(self,data): 50 | #Append the most recent node to the end 51 | ptr = self.head 52 | if(ptr == None): 53 | self.head = Element(data,self.head) 54 | else: 55 | while ptr.next: 56 | ptr=ptr.next 57 | ptr.next = Element(data, None) 58 | 59 | def deQueue(self): 60 | #move head ptr and return previous head 61 | if(self.head == None): 62 | return None 63 | ptr = self.head 64 | self.head = self.head.next 65 | ptr.next = None 66 | return ptr.data 67 | 68 | if __name__ == '__main__': 69 | myQ = Queue() 70 | 71 | for data in [1,2,3,4]: 72 | myQ.enQueue(data) 73 | 74 | print(myQ) 75 | 76 | print(myQ.getLast()) 77 | print(myQ) 78 | #for key in ['First','Second','Third','Fourth','Fifth']: 79 | # print("%s element out: %s" % (key,myQ.deQueue())) 80 | # print (myQ) 81 | # 82 | #print("Test Empty: %s"%myQ.deQueue()) 83 | #print (myQ) 84 | # 85 | #print("_______") 86 | #for data in [1,2,3,4]: 87 | # print("Adding %s" % data) 88 | # myQ.enQueue(data) 89 | # print(myQ) 90 | # print("Adding %s" % data) 91 | # myQ.enQueue(data) 92 | # print(myQ) 93 | # print("Removing %s"%myQ.deQueue()) 94 | # print(myQ) 95 | # 96 | #print(myQ) 97 | #print("_______") 98 | # 99 | #first = myQ.deQueue() 100 | #while first != None: 101 | # print("Removing %s"% first) 102 | # print(myQ) 103 | # first = myQ.deQueue() -------------------------------------------------------------------------------- /Trees/ADTs/Stack.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/17/2013 4 | 5 | # Typical stack, all operations act on the head/top of the stack. 6 | 7 | class Element: 8 | def __init__(self, data, next): 9 | self.data = data 10 | self.next = next 11 | 12 | class Stack: 13 | def __init__(self): 14 | self.head = None 15 | def __str__(self): 16 | ptr = self.head 17 | string = "TOP\n" 18 | if(self.head): 19 | while ptr: 20 | string += ("%s\n"%ptr.data) 21 | ptr = ptr.next 22 | else: 23 | string += "Empty\n" 24 | return string 25 | 26 | def push(self, element): 27 | self.head = Element(element, self.head) 28 | 29 | 30 | def pop(self): 31 | if self.empty(): return None 32 | result = self.head.data 33 | self.head = self.head.next 34 | return result 35 | 36 | def empty(self): 37 | return self.head == None 38 | 39 | if __name__ == "__main__": 40 | 41 | myS = Stack() 42 | for data in [1,2,3,4,5]: 43 | myS.push(data) 44 | 45 | print(myS) 46 | 47 | for key in ['First','Second','Third','Fourth','Fifth']: 48 | print("%s element out: %s" % (key,myS.pop())) 49 | print (myS) 50 | 51 | print("Test Empty: %s"%myS.pop()) 52 | print (myS) 53 | 54 | print("_______") 55 | for data in [1,2,3,4]: 56 | print("Adding %s" % data) 57 | myS.push(data) 58 | print(myS) 59 | print("Adding %s" % data) 60 | myS.push(data) 61 | print(myS) 62 | print("Removing %s"%myS.pop()) 63 | print(myS) 64 | 65 | print(myS) 66 | print("_______") 67 | 68 | first = myS.pop() 69 | while first != None: 70 | print("Removing %s"% first) 71 | print(myS) 72 | first = myS.pop() 73 | -------------------------------------------------------------------------------- /Trees/ADTs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirob2005/Python_Data_Structures/2851dc124e9b52391842521e584bf5ce716f3740/Trees/ADTs/__init__.py -------------------------------------------------------------------------------- /Trees/BST_iterative.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/19/2013 4 | 5 | # Implements a Binary Search Tree that uses a queue for BFS traversal, 6 | # and a stack for DFS traversals. Alternates between replacing a deleted 7 | # node with the inorder predecessor and inorder successor to help 8 | # balancing. The stack allows me to avoid recursion in this implementation. 9 | 10 | from ADTs.Queue_head import Queue 11 | from ADTs.Stack import Stack 12 | 13 | class Node: 14 | def __init__(self,key,left,right,parent): 15 | self.key = key 16 | self.left = left 17 | self.right = right 18 | self.parent = parent 19 | 20 | class BST: 21 | def __init__(self): 22 | self.root = None 23 | #Use this to alternate between replacing nodes with inorder 24 | #successor and predecessor 25 | self.replaceWithSuccessor = False 26 | 27 | def __str__(self): 28 | string = ("BFS: %s\n" % self.printBFS()) 29 | string += ("DFS (Preorder): %s\n" % self.printDFSpreorder()) 30 | string += ("DFS (Inorder): %s\n" % self.printDFSinorder()) 31 | string += ("DFS (Postorder): %s\n" % self.printDFSpostorder()) 32 | return string 33 | 34 | def printBFS(self): 35 | return str(self.traverseBFS()) 36 | 37 | def printDFSpreorder(self): 38 | return str(self.traverseDFSpreorder()) 39 | 40 | def printDFSinorder(self): 41 | return str(self.traverseDFSinorder()) 42 | 43 | def printDFSpostorder(self): 44 | return str(self.traverseDFSpostorder()) 45 | 46 | def insert(self, key): 47 | if(self.root == None): 48 | self.root = Node(key,None,None,None) 49 | return True 50 | else: 51 | ptr = self.root 52 | while ptr: 53 | if(key < ptr.key): 54 | if(ptr.left == None): 55 | ptr.left = Node(key, None, None, ptr) 56 | return True 57 | else: 58 | ptr = ptr.left 59 | elif(key > ptr.key): 60 | if(ptr.right == None): 61 | ptr.right = Node(key, None, None, ptr) 62 | return True 63 | else: 64 | ptr = ptr.right 65 | else: 66 | return False 67 | 68 | def insertList(self, alist): 69 | boolResult = True 70 | for item in alist: 71 | boolResult = boolResult and self.insert(item) 72 | return boolResult 73 | 74 | def find(self, key): 75 | ptr = self.root 76 | while ptr: 77 | if(key == ptr.key): 78 | return True 79 | elif(key > ptr.key): 80 | ptr = ptr.right 81 | else: 82 | ptr = ptr.left 83 | return False 84 | 85 | def delete(self, key): 86 | #alternate between using inorder predecessor and successor 87 | ptr = self.root 88 | while ptr: 89 | if(key == ptr.key): 90 | #If leaf node: 91 | if(not ptr.left and not ptr.right): 92 | #root node 93 | if(not ptr.parent): 94 | self.root = None 95 | elif(ptr.parent.right == ptr): 96 | ptr.parent.right = None 97 | else: 98 | ptr.parent.left = None 99 | ptr = None 100 | return True 101 | #If only 1 child (right) 102 | elif(not ptr.left and ptr.right): 103 | #root node 104 | if(not ptr.parent): 105 | self.root = ptr.right 106 | elif(ptr.parent.right == ptr): 107 | ptr.parent.right = ptr.right 108 | else: 109 | ptr.parent.left = ptr.right 110 | ptr.right.parent = ptr.parent 111 | ptr = None 112 | return True 113 | #If only 1 child (left) 114 | elif(ptr.left and not ptr.right): 115 | #root node 116 | if(not ptr.parent): 117 | self.root = ptr.left 118 | if(ptr.parent.right == ptr): 119 | ptr.parent.right = ptr.left 120 | else: 121 | ptr.parent.left = ptr.left 122 | ptr.left.parent = ptr.parent 123 | ptr = None 124 | return True 125 | #If 2 children 126 | else: 127 | if(self.replaceWithSuccessor): 128 | #Greatest Right Child (inorder successor) 129 | childptr = ptr.right 130 | while childptr.left: 131 | childptr = childptr.left 132 | ptr.key = childptr.key 133 | #if replacement node has a right child 134 | if(childptr.right): 135 | if(childptr.parent.right == childptr): 136 | childptr.parent.right = childptr.right 137 | else: 138 | childptr.parent.left = childptr.right 139 | childptr.right.parent = childptr.parent 140 | else: 141 | if(childptr.parent.right == childptr): 142 | childptr.parent.right = None 143 | else: 144 | childptr.parent.left = None 145 | childptr = None 146 | else: 147 | #Greatest Left Child (inorder predecessor) 148 | childptr = ptr.left 149 | while childptr.right: 150 | childptr = childptr.right 151 | ptr.key = childptr.key 152 | #if replacement node has a left child 153 | if(childptr.left): 154 | if(childptr.parent.right == childptr): 155 | childptr.parent.right = childptr.left 156 | else: 157 | childptr.parent.left = childptr.left 158 | childptr.left.parent = childptr.parent 159 | else: 160 | if(childptr.parent.right == childptr): 161 | childptr.parent.right = None 162 | else: 163 | childptr.parent.left = None 164 | childptr = None 165 | self.replaceWithSuccessor = not self.replaceWithSuccessor 166 | return True 167 | elif(key > ptr.key): 168 | ptr = ptr.right 169 | else: 170 | ptr = ptr.left 171 | return False 172 | 173 | def traverseBFS(self): 174 | keys = [] 175 | bfsQ = Queue() 176 | bfsQ.enQueue(self.root) 177 | cur = bfsQ.deQueue() 178 | while cur: 179 | #print("cur.key = %s"%cur.key) 180 | keys.append(cur.key) 181 | #print("%s added to keys" % str(cur.key)) 182 | if(cur.left): 183 | bfsQ.enQueue(cur.left) 184 | #print('cur.left.key = %s' % cur.left.key) 185 | if(cur.right): 186 | bfsQ.enQueue(cur.right) 187 | #print("cur.right.key = %s"%cur.right.key) 188 | cur = bfsQ.deQueue() 189 | #print("--------------------------------") 190 | return keys 191 | 192 | def traverseDFSpreorder(self): 193 | #root, left subtree, right subtree 194 | keys = [] 195 | dfsS = Stack() 196 | dfsS.push(self.root) 197 | cur = dfsS.pop() 198 | while cur: 199 | #print("cur.key = %s"%cur.key) 200 | keys.append(cur.key) 201 | #print("%s added to keys" % str(cur.key)) 202 | if(cur.right): 203 | dfsS.push(cur.right) 204 | #print("cur.right.key = %s"%cur.right.key) 205 | if(cur.left): 206 | dfsS.push(cur.left) 207 | #print('cur.left.key = %s' % cur.left.key) 208 | cur = dfsS.pop() 209 | #print("--------------------------------") 210 | return keys 211 | 212 | def traverseDFSinorder(self): 213 | #left subtree, root, right subtree 214 | keys = [] 215 | dfsS = Stack() 216 | dfsS.push(self.root) 217 | cur = dfsS.pop() 218 | while cur: 219 | #print("cur.key = %s"%cur.key) 220 | if((not cur.left) or (cur.left.key in keys)): 221 | keys.append(cur.key) 222 | #print("%s added to keys" % str(cur.key)) 223 | if(cur.right): 224 | dfsS.push(cur.right) 225 | #print("cur.right.key = %s"%cur.right.key) 226 | else: 227 | dfsS.push(cur) 228 | if(cur.left and cur.left.key not in keys): 229 | dfsS.push(cur.left) 230 | #print('cur.left.key = %s' % cur.left.key) 231 | cur = dfsS.pop() 232 | #print("--------------------------------") 233 | return keys 234 | 235 | def traverseDFSpostorder(self): 236 | #left subtree, right subtree, root 237 | keys = [] 238 | dfsS = Stack() 239 | dfsS.push(self.root) 240 | cur = dfsS.pop() 241 | while cur: 242 | #print("cur.key = %s"%cur.key) 243 | if(((not cur.left) or (cur.left.key in keys)) and ((not cur.right) or (cur.right.key in keys))): 244 | keys.append(cur.key) 245 | #print("%s added to keys" % str(cur.key)) 246 | else: 247 | dfsS.push(cur) 248 | if(cur.right): 249 | dfsS.push(cur.right) 250 | #print("cur.right.key = %s"%cur.right.key) 251 | if(cur.left): 252 | dfsS.push(cur.left) 253 | #print('cur.left.key = %s' % cur.left.key) 254 | cur = dfsS.pop() 255 | #print("--------------------------------") 256 | return keys 257 | 258 | def copyTree(self): 259 | copy = BST() 260 | copy.insertList(self.traverseDFSpreorder()) 261 | return copy 262 | 263 | def findMin(self): 264 | if(not self.root): 265 | return None 266 | ptr = self.root 267 | while ptr.left: 268 | ptr = ptr.left 269 | return ptr.key 270 | 271 | def findMax(self): 272 | if(not self.root): 273 | return None 274 | ptr = self.root 275 | while ptr.right: 276 | ptr = ptr.right 277 | return ptr.key -------------------------------------------------------------------------------- /Trees/BST_recursive.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/21/2013 4 | 5 | # Implements a Binary Search Tree that uses a queue for BFS traversal, 6 | # and recursion for DFS traversals. Alternates between replacing a deleted 7 | # node with the inorder predecessor and inorder successor to help 8 | # balancing. Inherits BFS, insertList, __str__, print methods, and Node 9 | # class from iterative approach since recursion is not needed for these. 10 | 11 | from BST_iterative import BST as BST_iter 12 | from BST_iterative import Node 13 | 14 | class BST(BST_iter): 15 | def insert(self, key, root=None): 16 | if(not self.root): 17 | self.root = Node(key,None,None,None) 18 | return True 19 | if(not root): 20 | root = self.root 21 | if(key == root.key): 22 | return False 23 | elif(key > root.key): 24 | if(not root.right): 25 | root.right = Node(key,None,None,root) 26 | return True 27 | newRoot = root.right 28 | else: 29 | if(not root.left): 30 | root.left = Node(key,None,None,root) 31 | return True 32 | newRoot = root.left 33 | return self.insert(key, newRoot) 34 | 35 | def find(self, key, root=None): 36 | if(not root): 37 | if(not self.root): 38 | return False 39 | root = self.root 40 | if(key == root.key): 41 | return True 42 | elif(key > root.key): 43 | if(not root.right): 44 | return False 45 | return self.find(key,root.right) 46 | else: 47 | if(not root.left): 48 | return False 49 | return self.find(key,root.left) 50 | 51 | def delete(self, key, root=None): 52 | #alternate between using inorder predecessor and successor 53 | if(not root): 54 | if(not self.root): 55 | return False 56 | root = self.root 57 | if(key == root.key): 58 | #If leaf node: 59 | if(not root.left and not root.right): 60 | #root node 61 | if(not root.parent): 62 | self.root = None 63 | elif(root.parent.right == root): 64 | root.parent.right = None 65 | else: 66 | root.parent.left = None 67 | root = None 68 | return True 69 | #If only 1 child (right) 70 | elif(not root.left and root.right): 71 | #root node 72 | if(not root.parent): 73 | self.root = root.right 74 | elif(root.parent.right == root): 75 | root.parent.right = root.right 76 | else: 77 | root.parent.left = root.right 78 | root.right.parent = root.parent 79 | root = None 80 | return True 81 | #If only 1 child (left) 82 | elif(root.left and not root.right): 83 | #root node 84 | if(not root.parent): 85 | self.root = root.left 86 | if(root.parent.right == root): 87 | root.parent.right = root.left 88 | else: 89 | root.parent.left = root.left 90 | root.left.parent = root.parent 91 | root = None 92 | return True 93 | #If 2 children 94 | else: 95 | if(self.replaceWithSuccessor): 96 | #Greatest Right Child (inorder successor) 97 | childptr = root.right 98 | while childptr.left: 99 | childptr = childptr.left 100 | root.key = childptr.key 101 | #if replacement node has a right child 102 | if(childptr.right): 103 | if(childptr.parent.right == childptr): 104 | childptr.parent.right = childptr.right 105 | else: 106 | childptr.parent.left = childptr.right 107 | childptr.right.parent = childptr.parent 108 | else: 109 | if(childptr.parent.right == childptr): 110 | childptr.parent.right = None 111 | else: 112 | childptr.parent.left = None 113 | childptr = None 114 | else: 115 | #Greatest Left Child (inorder predecessor) 116 | childptr = root.left 117 | while childptr.right: 118 | childptr = childptr.right 119 | root.key = childptr.key 120 | #if replacement node has a left child 121 | if(childptr.left): 122 | if(childptr.parent.right == childptr): 123 | childptr.parent.right = childptr.left 124 | else: 125 | childptr.parent.left = childptr.left 126 | childptr.left.parent = childptr.parent 127 | else: 128 | if(childptr.parent.right == childptr): 129 | childptr.parent.right = None 130 | else: 131 | childptr.parent.left = None 132 | childptr = None 133 | self.replaceWithSuccessor = not self.replaceWithSuccessor 134 | return True 135 | elif(key > root.key): 136 | if(root.right): 137 | return self.delete(key, root.right) 138 | else: 139 | if(root.left): 140 | return self.delete(key,root.left) 141 | return False 142 | 143 | def traverseDFSpreorder(self, root = True): 144 | # Enables inheritance from BST_iterative (assumes root if none provided) 145 | if(root == True): 146 | root = self.root 147 | #root, left subtree, right subtree 148 | if(not root): 149 | return [] 150 | return [root.key] + self.traverseDFSpreorder(root.left) + self.traverseDFSpreorder(root.right) 151 | 152 | def traverseDFSinorder(self, root = True): 153 | # Enables inheritance from BST_iterative (assumes root if none provided) 154 | if(root == True): 155 | root = self.root 156 | #left, root, right subtree 157 | if(not root): 158 | return [] 159 | return self.traverseDFSinorder(root.left) + [root.key] + self.traverseDFSinorder(root.right) 160 | 161 | def traverseDFSpostorder(self, root = True): 162 | # Enables inheritance from BST_iterative (assumes root if none provided) 163 | if(root == True): 164 | root = self.root 165 | #left, right, root 166 | if(not root): 167 | return [] 168 | return self.traverseDFSpostorder(root.left) + self.traverseDFSpostorder(root.right) + [root.key] 169 | 170 | def findMin(self, root=None): 171 | if(not root): 172 | if(not self.root): 173 | return None 174 | root = self.root 175 | if(root.left): 176 | return self.findMin(root.left) 177 | return root.key 178 | 179 | def findMax(self, root=None): 180 | if(not root): 181 | if(not self.root): 182 | return None 183 | root = self.root 184 | if(root.right): 185 | return self.findMax(root.right) 186 | return root.key -------------------------------------------------------------------------------- /Trees/Binary_Heap_Tree_Structure.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 2/23/2013 4 | 5 | # This uses a queue for BFS traversal for printing purposes. 6 | # It also uses a modified queue to keep track of nodes that will 7 | # be future subroots/parents. If the current parent's children is 8 | # full we grab the next item in the queue to be the parent for the 9 | # upcoming children. Each time we add a node, we add it to the 10 | # queue. Each time we delete, we delete the last item added to 11 | # the queue hence the need to have a getLast() method. 12 | # It uses a stack to keep track of parents who's children were 13 | # recently filled in. Need this so we can backtrack to these 14 | # previously filled parents in the case of deletes. We then put 15 | # the parent we were on before backtracking back into the 16 | # queue but in the front of the line for inserting once again 17 | # hence the need for the insert() method. 18 | 19 | from ADTs.Queue_modified_for_heap_use import Queue 20 | from ADTs.Stack import Stack 21 | 22 | class Node: 23 | def __init__(self, key, parent, left, right): 24 | self.key = key 25 | self.parent = parent 26 | self.left = left 27 | self.right = right 28 | 29 | class BinaryHeap: 30 | def __init__(self): 31 | self.root = None 32 | self.current = None 33 | self.queue = Queue() 34 | self.past = Stack() 35 | 36 | def __str__(self): 37 | return self.traverseBFS() 38 | 39 | def traverseBFS(self): 40 | string = "" 41 | bfsQ = Queue() 42 | bfsQ.enQueue(self.root) 43 | cur = bfsQ.deQueue() 44 | while cur: 45 | string += ("\n%s - (%s|%s, %s)"%(cur.key, 46 | cur.parent.key if cur.parent else None, 47 | cur.left.key if cur.left else None, 48 | cur.right.key if cur.right else None)) 49 | if(cur.left): 50 | bfsQ.enQueue(cur.left) 51 | if(cur.right): 52 | bfsQ.enQueue(cur.right) 53 | cur = bfsQ.deQueue() 54 | if(string == ""): 55 | string = "(Empty)" 56 | return string 57 | 58 | def insert(self, key): 59 | if(not self.root): 60 | self.root = Node(key, None, None, None) 61 | self.current = self.root 62 | #print("Stacking %d"%self.current.key) 63 | self.past.push(self.current) 64 | return True 65 | if(self.current.left and self.current.right): 66 | self.current = self.queue.deQueue() 67 | #print("DeQ %d"%self.current.key) 68 | #print("Stacking %d"%self.current.key) 69 | self.past.push(self.current) 70 | if(not self.current.left): 71 | self.current.left = Node(key, self.current,None,None) 72 | #print("Qing1 %d"%self.current.left.key) 73 | self.queue.enQueue(self.current.left) 74 | self.heapifyUp(self.current.left) 75 | return True 76 | elif(not self.current.right): 77 | self.current.right = Node(key, self.current,None,None) 78 | self.queue.enQueue(self.current.right) 79 | #print("Qing2 %d"%self.current.right.key) 80 | self.heapifyUp(self.current.right) 81 | return True 82 | return False 83 | 84 | def insertList(self, alist): 85 | boolResult = True 86 | for item in alist: 87 | if(self.insert(item) == False): 88 | boolResult = False 89 | return boolResult 90 | 91 | def heapifyUp(self, node): 92 | while(node.parent and node.key > node.parent.key): 93 | temp = node.parent.key 94 | node.parent.key = node.key 95 | node.key = temp 96 | node = node.parent 97 | 98 | def delete(self): 99 | if(not self.root): 100 | return None 101 | returnValue = self.root.key 102 | if(self.current.right): 103 | self.root.key = self.current.right.key 104 | self.current.right.parent = None 105 | self.current.right = None 106 | returned = self.queue.getLast() 107 | #print("deQing %s"%returned.key) 108 | elif(self.current.left): 109 | if(self.current == self.root): 110 | self.root.key = self.current.left.key 111 | self.current.left.parent = None 112 | self.current.left = None 113 | returned = self.queue.getLast() 114 | #print("deQing %s"%returned.key) 115 | else: 116 | self.root.key = self.current.left.key 117 | self.current.left.parent = None 118 | self.current.left = None 119 | returned = self.queue.getLast() 120 | #print("deQing %s"%returned.key) 121 | pop = self.past.pop() 122 | #print("Popping and inserting %s"%pop.key) 123 | self.queue.insert(pop) 124 | self.current = self.past.pop() 125 | self.past.push(self.current) 126 | else: 127 | pop = self.past.pop() 128 | #print("Popping%s"%pop.key) 129 | self.root = None 130 | self.heapifyDown(self.root) 131 | return returnValue 132 | 133 | def heapifyDown(self, ptr): 134 | #root is none, or no children to swap 135 | if(not ptr or (not ptr.left and not ptr.right)): 136 | return 137 | if(not ptr.right or ptr.left.key > ptr.right.key): 138 | if(ptr.left.key > ptr.key): 139 | temp = ptr.key 140 | ptr.key = ptr.left.key 141 | ptr.left.key = temp 142 | ptr = ptr.left 143 | else: 144 | return 145 | else: 146 | if(ptr.right.key > ptr.key): 147 | temp = ptr.key 148 | ptr.key = ptr.right.key 149 | ptr.right.key = temp 150 | ptr = ptr.right 151 | else: 152 | return 153 | self.heapifyDown(ptr) 154 | 155 | def merge(self, heap): 156 | heapData = heap.returnBFS() 157 | self.insertList(heapData) 158 | 159 | def peek(self): 160 | return self.root.key if self.root else None 161 | 162 | def returnBFS(self): 163 | keys = [] 164 | bfsQ = Queue() 165 | bfsQ.enQueue(self.root) 166 | cur = bfsQ.deQueue() 167 | while cur: 168 | keys.append(cur.key) 169 | if(cur.left): 170 | bfsQ.enQueue(cur.left) 171 | if(cur.right): 172 | bfsQ.enQueue(cur.right) 173 | cur = bfsQ.deQueue() 174 | return keys 175 | 176 | def copyHeap(self): 177 | copy = BinaryHeap() 178 | copy.insertList(self.returnBFS()) 179 | return copy 180 | 181 | if __name__ == '__main__': 182 | 183 | bh = BinaryHeap() 184 | 185 | bh.insert(0) 186 | print("After Inserting %d : %s\n"%(0,bh)) 187 | bh.insert(1) 188 | print("After Inserting %d :%s\n"%(1,bh)) 189 | returned = bh.delete() 190 | print("After Delete %d: %s\n"%(returned,bh)) 191 | 192 | bh.insert(2) 193 | print("After Inserting %d : %s\n"%(2,bh)) 194 | bh.insert(3) 195 | print("After Inserting %d :%s\n"%(3,bh)) 196 | returned = bh.delete() 197 | print("After Delete %d: %s\n"%(returned,bh)) 198 | 199 | bh.insert(4) 200 | print("After Inserting %d : %s\n"%(4,bh)) 201 | bh.insert(5) 202 | print("After Inserting %d :%s\n"%(5,bh)) 203 | returned = bh.delete() 204 | print("After Delete %d: %s\n"%(returned,bh)) 205 | 206 | returned = bh.delete() 207 | print("After Delete %d: %s\n"%(returned,bh)) 208 | 209 | returned = bh.delete() 210 | print("After Delete %d: %s\n"%(returned,bh)) 211 | 212 | returned = bh.delete() 213 | print("After Delete %d: %s\n"%(returned,bh)) 214 | 215 | bh.insert(6) 216 | print("After Inserting %d : %s\n"%(6,bh)) 217 | bh.insert(7) 218 | print("After Inserting %d :%s\n"%(7,bh)) 219 | bh.insert(8) 220 | print("After Inserting %d :%s\n"%(8,bh)) 221 | bh.insert(9) 222 | print("After Inserting %d :%s\n"%(9,bh)) 223 | 224 | print("PEEK %s"%bh.peek()) 225 | print(bh) 226 | 227 | bh2 = BinaryHeap() 228 | bh2.insertList([1,2,3,10,7]) 229 | bh.merge(bh2) 230 | print(bh) 231 | print(bh2) -------------------------------------------------------------------------------- /Trees/README.md: -------------------------------------------------------------------------------- 1 | # *Trees:* 2 | ## *Binary Search Tree:* 3 | ### *Operations:* 4 | - insert 5 | - insertList 6 | - find 7 | - delete 8 | - traverseBFS 9 | - traverseDFSpreorder 10 | - traverseDFSinorder 11 | - traverseDFSpostorder 12 | - copyTree 13 | - findMin 14 | - findMax 15 | 16 | ### *Types:* 17 | - Iterative (uses Queue(head ptr) and Stack for traversals) 18 | - Recursive (inherits from iterative approach, reimplements insert,find,delete,DFS,findMin,findMax) 19 | 20 | Unit Tests to test each operation for both types 21 | 22 | ## *Binary Heap:* 23 | ### *Operations:* 24 | - traverseBFS 25 | - insert (with heapifyUp to ensure heap property) 26 | - insertList 27 | - delete (with heapifyDown to ensure heap property) 28 | - merge (2 heaps -> 1 heap) 29 | - peek (get max value) 30 | - copyHeap 31 | 32 | ### *Types:* 33 | - Tree Structure (uses ptrs) 34 | - Array Structure (no ptrs needed) in ADT directory 35 | 36 | Units Tests to test each operation and to ensure proper tracking 37 | of next insert/delete location to ensure shape property 38 | 39 | ## *Trie:* 40 | ### *Operations:* 41 | - traverse(Words|Prefixes) - Outputs words for generic type or all prefixes for prefix count versions 42 | - traverseBFS 43 | - add 44 | - remove 45 | - isMember (full words or prefixes specifically added) 46 | - updateValue (Generic type only) 47 | - getValue 48 | 49 | ### *Types:* 50 | - Generic - allows adding words with a corresponding value, all prefix node values are None 51 | - Prefix Count - user only adds words, values correspond to number of times that prefix is used 52 | - Prefix Count Speed - Same as above, but using more space to allow for faster indexing 53 | 54 | Unit tests to test each operation for all 3 types 55 | 56 | # *Self-Balancing BST's:* 57 | ## *AVL Tree:* 58 | ### *Operations:* 59 | - insert (Balance Factor Calculations added) 60 | - delete (Balance Factor Calculations added) 61 | - deleteTree (new, none of the other trees has this added at this time) 62 | - checkBalance (check the Balance Factor to see if a rotation(s) is necessary) 63 | - calcBF (recalculate the BF for the the given root and all ancestors if necessary, insert version and delete version) 64 | - rotateLeft 65 | - rotateRight 66 | 67 | - All redefined operations are recursive. 68 | 69 | ### *Rest of the operations are inherited from the recursive BST* 70 | 71 | Unit Tests to test each operation and valid rotations. 72 | 73 | ## *Red-Black Tree:* 74 | ### *Operations:* 75 | - insert (Color Check added) 76 | - delete (Color Check added) 77 | - deleteTree (Same as AVL) 78 | - checkColor (determines the new coloring and if any rotations are needed - version for post-insert and post-delete) 79 | - rotateLeft (Same as AVL) 80 | - rotateRight (Same as AVL) 81 | 82 | - All redefined operations are recursive. 83 | 84 | ### *Rest of the operations are inherited from the recursive BST* 85 | 86 | Unit Tests to test each operation, valid rotations and correct coloring. 87 | 88 | ## *Splay Tree:* 89 | ### *Operations:* 90 | - insert (splaying added) 91 | - find (splaying added for valid/invalid finds) 92 | - delete (splaying added for valid/invalid deletes) 93 | - copyTree (redefined due to the structure of the splay tree varying based off order of inserts) 94 | - findRecentAccessed (returns the root, only useful for a splay tree) 95 | - splay (rotates the tree so that the most recent inserted/found node or parent of a recent delete is rotated to the root) 96 | 97 | - All redefined operations are recursive. 98 | 99 | ### *Rest of the operations are inherited from the recursive BST* 100 | 101 | Unit Tests to test each operation and valid splaying. -------------------------------------------------------------------------------- /Trees/Splay_Tree.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 3/19/2013 4 | 5 | # Implements a Splay Tree that uses a method called splay that rotates the tree 6 | # so that the most recently accessed (insert/find) node is on the top of the 7 | # tree but maintains the requirements of a BST. In case of a deletion, the 8 | # parent of the deleted node is rotated to the root, if the parent exists. 9 | # Improves the worst case search, insert, delete of a BST from O(n) to O(log n) 10 | # amortized. 11 | # Inherits insertList, __str__, print methods, and Node 12 | # class indirectly from BST_iterative and the DFS traversals and find min/max 13 | # from BST_recursive 14 | # Delete replaces the deleted node with the inorder predecessor ONLY rather than 15 | # alternate between predecessor and successor like the BST approaches 16 | # A failed delete/find (i.e. value not found) still splays the tree using the last valid 17 | # node found. If our values range [1-10] and we try to delete/find value 0, we use 18 | # splay(1). Likewise, if we try to find/delete 11, we splay(10) 19 | # CopyTree is redefined from the BST approaches due to the fact that the splay tree 20 | # structure depends on the order of the inserts unlike BST's. So copying the tree via 21 | # insert will not work. 22 | 23 | # Time Complexity: 24 | # Search - avg O(log n) worst case: amortized O(log n) 25 | # Insert - avg O(log n) worst case: amortized O(log n) 26 | # Delete - avg O(log n) worst case: amortized O(log n) 27 | 28 | from BST_recursive import Node 29 | from BST_recursive import BST 30 | from ADTs.Queue_head import Queue 31 | 32 | class SplayTree(BST): 33 | def splay(self, node): 34 | parent = node.parent 35 | #print() 36 | #print("node = %s"%node.key) 37 | if node == self.root: 38 | #print("node is root") 39 | return 40 | #Node does NOT have a grandparent - ZIG 41 | elif parent == self.root: 42 | #print('ZIG') 43 | if node.key > parent.key: 44 | #print('node > parent') 45 | self.root = node 46 | parent.right = node.left 47 | node.left = parent 48 | node.parent = None 49 | parent.parent = node 50 | if parent.right != None: 51 | parent.right.parent = parent 52 | return 53 | else: 54 | #print('node < parent') 55 | self.root = node 56 | parent.left = node.right 57 | node.right = parent 58 | node.parent = None 59 | parent.parent = node 60 | if parent.left != None: 61 | parent.left.parent = parent 62 | return 63 | #Node DOES have a grandparent 64 | else: 65 | #print('node has gp') 66 | gparent = parent.parent 67 | if(node.key < parent.key and parent.key < gparent.key): 68 | #print('ZIG-ZIG') 69 | #print('BOTH LEFT') 70 | if gparent ==self.root: 71 | self.root = node 72 | node.parent = None 73 | else: 74 | if gparent.key < gparent.parent.key: 75 | gparent.parent.left = node 76 | else: 77 | gparent.parent.right = node 78 | node.parent = gparent.parent 79 | parent.left = node.right 80 | if parent.left != None: 81 | parent.left.parent = parent 82 | node.right = parent 83 | parent.parent = node 84 | gparent.left = parent.right 85 | if gparent.left != None: 86 | gparent.left.parent = gparent 87 | parent.right = gparent 88 | 89 | gparent.parent = parent 90 | elif(node.key > parent.key and parent.key > parent.parent.key): 91 | #print('ZIG-ZIG') 92 | #print('BOTH RIGHT') 93 | if gparent ==self.root: 94 | self.root = node 95 | node.parent = None 96 | else: 97 | if gparent.key < gparent.parent.key: 98 | gparent.parent.left = node 99 | else: 100 | gparent.parent.right = node 101 | node.parent = gparent.parent 102 | parent.right = node.left 103 | if parent.right != None: 104 | parent.right.parent = parent 105 | node.left = parent 106 | parent.parent = node 107 | gparent.right = parent.left 108 | if gparent.right != None: 109 | gparent.right.parent = gparent 110 | parent.left = gparent 111 | 112 | gparent.parent = parent 113 | else: 114 | #print('ZIG-ZAG') 115 | if gparent == self.root: 116 | self.root = node 117 | node.parent = None 118 | else: 119 | if gparent.key < gparent.parent.key: 120 | gparent.parent.left= node 121 | else: 122 | gparent.parent.right = node 123 | node.parent = gparent.parent 124 | if parent.key < gparent.key: 125 | #print('parent < gparent') 126 | parent.right = node.left 127 | if parent.right != None: 128 | parent.right.parent = parent 129 | node.left = parent 130 | parent.parent = node 131 | gparent.left = node.right 132 | if gparent.left != None: 133 | gparent.left.parent = gparent 134 | node.right = gparent 135 | 136 | gparent.parent = node 137 | else:#parent > gparent 138 | #print('parent > gparent') 139 | gparent.right = node.left 140 | if gparent.right != None: 141 | gparent.right.parent = gparent 142 | node.left = gparent 143 | gparent.parent = node 144 | parent.left = node.right 145 | if parent.left != None: 146 | parent.left.parent = parent 147 | node.right = parent 148 | 149 | parent.parent = node 150 | if self.root != node: 151 | #print('node is not root') 152 | #print('node = %s'%node.key) 153 | self.splay(node) 154 | #return 155 | #else: 156 | #print('node is root') 157 | 158 | #Splay the inserted node to the top 159 | def insert(self, key, root=None): 160 | if(not self.root): 161 | self.root = Node(key,None,None,None) 162 | return True 163 | if(not root): 164 | root = self.root 165 | if(key == root.key): 166 | self.splay(root) 167 | return False 168 | elif(key > root.key): 169 | if(not root.right): 170 | root.right = Node(key,None,None,root) 171 | self.splay(root.right) 172 | return True 173 | newRoot = root.right 174 | else: 175 | if(not root.left): 176 | root.left = Node(key,None,None,root) 177 | self.splay(root.left) 178 | return True 179 | newRoot = root.left 180 | return self.insert(key, newRoot) 181 | 182 | #Splay the found node to the top, or if not found, the last valid node to the top 183 | def find(self, key, root=None): 184 | if(not root): 185 | if(not self.root): 186 | return False 187 | root = self.root 188 | if(key == root.key): 189 | self.splay(root) 190 | return True 191 | elif(key > root.key): 192 | if(not root.right): 193 | self.splay(root) 194 | return False 195 | return self.find(key,root.right) 196 | else: 197 | if(not root.left): 198 | self.splay(root) 199 | return False 200 | return self.find(key,root.left) 201 | 202 | #Splay the parent of the deleted key to the root if parent exists 203 | def delete(self, key, root=None): 204 | #replace using inorder predecessor 205 | if(not root): 206 | if(not self.root): 207 | return False 208 | root = self.root 209 | if(key == root.key): 210 | #If leaf node: 211 | if(not root.left and not root.right): 212 | #root node 213 | if(not root.parent): 214 | self.root = None 215 | return True 216 | elif(root.parent.right == root): 217 | root.parent.right = None 218 | else: 219 | root.parent.left = None 220 | parent = root.parent 221 | root = None 222 | self.splay(parent) 223 | return True 224 | #If only 1 child (right) 225 | elif(not root.left and root.right): 226 | #root node 227 | if(not root.parent): 228 | self.root = root.right 229 | self.root.parent = None 230 | return True 231 | elif(root.parent.right == root): 232 | root.parent.right = root.right 233 | else: 234 | root.parent.left = root.right 235 | root.right.parent = root.parent 236 | parent = root.parent 237 | root = None 238 | self.splay(parent) 239 | return True 240 | #If only 1 child (left) 241 | elif(root.left and not root.right): 242 | #root node 243 | if(not root.parent): 244 | self.root = root.left 245 | self.root.parent = None 246 | return True 247 | if(root.parent.right == root): 248 | root.parent.right = root.left 249 | else: 250 | root.parent.left = root.left 251 | root.left.parent = root.parent 252 | parent = root.parent 253 | root = None 254 | self.splay(parent) 255 | return True 256 | #If 2 children 257 | else: 258 | #Greatest Left Child (inorder predecessor) 259 | childptr = root.left 260 | while childptr.right: 261 | childptr = childptr.right 262 | root.key = childptr.key 263 | #if replacement node has a left child 264 | if(childptr.left): 265 | if(childptr.parent.right == childptr): 266 | childptr.parent.right = childptr.left 267 | else: 268 | childptr.parent.left = childptr.left 269 | childptr.left.parent = childptr.parent 270 | else: 271 | if(childptr.parent.right == childptr): 272 | childptr.parent.right = None 273 | else: 274 | childptr.parent.left = None 275 | childParent = childptr.parent 276 | childptr = None 277 | if(childParent): 278 | self.splay(childParent) 279 | #root node 280 | else: 281 | self.root.parent = None 282 | return True 283 | elif(key > root.key): 284 | if(root.right): 285 | return self.delete(key, root.right) 286 | else: 287 | if(root.left): 288 | return self.delete(key,root.left) 289 | #Tree is splayed using the last checked root even on a delete failure 290 | self.splay(root) 291 | return False 292 | 293 | def traverseBFS(self): 294 | string = '' 295 | bfsQ = Queue() 296 | bfsQ.enQueue(self.root) 297 | cur = bfsQ.deQueue() 298 | while cur: 299 | string += ('(%s)<-'%cur.parent.key if cur.parent else '(None)<-') 300 | string += str(cur.key) 301 | string += ('->(%s,'%cur.left.key if cur.left else '->(None,') 302 | string += ('%s)\n'%cur.right.key if cur.right else 'None)\n') 303 | if(cur.left): 304 | bfsQ.enQueue(cur.left) 305 | if(cur.right): 306 | bfsQ.enQueue(cur.right) 307 | cur = bfsQ.deQueue() 308 | if string == '': 309 | string = '(Empty)' 310 | return string 311 | 312 | def findRecentAccessed(self): 313 | if self.root: 314 | return self.root.key 315 | else: 316 | return None 317 | 318 | #Must be redefined from the BST approach, because the tree will be structured 319 | # different depending on the order of insert unlike a common BST 320 | def copyTree(self): 321 | copy = SplayTree() 322 | cur = self.root 323 | if cur: 324 | copy.root = Node(cur.key, None, None, None) 325 | self.copy(cur, copy.root) 326 | return copy 327 | 328 | def copy(self, cur, copyCur): 329 | if cur.left: 330 | copyCur.left = Node(cur.left.key,None,None,copyCur) 331 | self.copy(cur.left,copyCur.left) 332 | if cur.right: 333 | copyCur.right = Node(cur.right.key,None,None,copyCur) 334 | self.copy(cur.right,copyCur.right) 335 | 336 | if __name__ == '__main__': 337 | st = SplayTree() 338 | 339 | for value in [10,15,5,6,9,7,12,1,3]: 340 | st.insert(value) 341 | 342 | st.find(7) 343 | 344 | print('--------------------') 345 | copy = st.copyTree() 346 | st.find(5) 347 | copy.find(10) 348 | print("Modified Original:\n") 349 | print(st.traverseBFS()) 350 | print('^^^^^^^^^^^^') 351 | print("Modified Copy:\n") 352 | print(copy.traverseBFS()) 353 | print(st.findRecentAccessed()) -------------------------------------------------------------------------------- /Trees/Trie.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 3/3/2013 4 | 5 | #Trie is built using a Tree-like structure 6 | #Each node contains a single character and possibly a value 7 | #Each word can be created by going from the root down any branch to a 8 | # terminating node or a node with a value(for prefixes) 9 | #The traverseWords method goes through each branch and strings together 10 | # the words added to the trie by using the logic above. 11 | 12 | from ADTs.Queue_head import Queue 13 | from ADTs.Stack import Stack 14 | 15 | class Node: 16 | def __init__(self,key,value): 17 | self.key = key 18 | self.value = value 19 | self.next = [] 20 | 21 | class Trie: 22 | def __init__(self): 23 | self.root = Node(None,None) 24 | self.output = '' 25 | 26 | def __str__(self): 27 | string = "BFS: %s"%str(self.traverseBFS()) 28 | string += "\nWords: %s"%str(self.traverseWords()) 29 | return string 30 | 31 | def __contains__(self, key): 32 | pass 33 | 34 | 35 | def traverseWords(self): 36 | self.output = '' 37 | if not self.root.next: 38 | self.output = 'Empty' 39 | for child in self.root.next: 40 | self.traverse(child,'') 41 | return self.output.rstrip(', ') 42 | 43 | def traverse(self,root,prefix): 44 | prefix += root.key 45 | for node in root.next: 46 | if node.next and not node.value: 47 | self.traverse(node,prefix) 48 | elif node.next and node.value: 49 | self.output += prefix + node.key + ' '# + (" (%s), "%node.value) 50 | self.traverse(node,prefix) 51 | else: 52 | self.output += prefix + node.key + ' '# + (" (%s), "%node.value) 53 | 54 | def traverseBFS(self): 55 | keys = [] 56 | bfsQ = Queue() 57 | bfsQ.enQueue(self.root) 58 | cur = bfsQ.deQueue() 59 | while cur: 60 | if(cur != self.root): 61 | keys.append(cur.key) 62 | for node in cur.next: 63 | bfsQ.enQueue(node) 64 | cur = bfsQ.deQueue() 65 | return ', '.join([str(key) for key in keys]) 66 | 67 | #IF key already exists, it just updates the value 68 | def add(self, key, value, root=None): 69 | if not type(key) == str: 70 | return False 71 | if not key: 72 | root.value = value 73 | return True 74 | if not root: 75 | root = self.root 76 | for node in root.next: 77 | if key[0] in node.key: 78 | return self.add(key[1:],value,root.next[root.next.index(node)]) 79 | root.next.append(Node(key[0],None)) 80 | return self.add(key[1:],value,root.next[-1]) 81 | 82 | def remove(self, key): 83 | if not self.isMember(key, self.root): 84 | return False 85 | return self.removeHelper(key, self.root,0) 86 | 87 | def removeHelper(self,key,root,index): 88 | for node in root.next: 89 | if key[index] in node.key: 90 | #No next neighbors and value is set 91 | #Delete the element completely and recurse back and test previous index 92 | if not node.next and node.value != None: 93 | del root.next[root.next.index(node)] 94 | self.removeHelper(key,root,index-1) 95 | #Last element in key with a next neighbor and the value is set 96 | #Clear the value and DONE 97 | elif index == len(key)-1 and node.next and node.value != None: 98 | node.value = None 99 | return True 100 | else: 101 | #Not the last key and there is a next neighbor, recurse further 102 | self.removeHelper(key,node,index+1) 103 | #This runs after the last element is deleted, and proccesses 104 | #earlier nodes to check if they also need deleted 105 | if not node.next and node.value == None: 106 | del root.next[root.next.index(node)] 107 | return True 108 | return False 109 | 110 | def isMember(self, key, root=None): 111 | if not type(key) == str or not key: 112 | return False 113 | if not root: 114 | root = self.root 115 | for node in root.next: 116 | if key[0] in node.key: 117 | if len(key) == 1 and node.value: 118 | return True 119 | else: 120 | return self.isMember(key[1:],root.next[root.next.index(node)]) 121 | return False 122 | 123 | def updateValue(self,key,value, root=None): 124 | if not type(key) == str or not key: 125 | return False 126 | if not root: 127 | root = self.root 128 | for node in root.next: 129 | if key[0] in node.key: 130 | if len(key) == 1: 131 | node.value = value 132 | return True 133 | else: 134 | return self.updateValue(key[1:],value,root.next[root.next.index(node)]) 135 | return False 136 | 137 | def getValue(self,key,root=None): 138 | if not type(key) == str or not key: 139 | return None 140 | if not root: 141 | root = self.root 142 | for node in root.next: 143 | if key[0] in node.key: 144 | if len(key) == 1 and node.value: 145 | return node.value 146 | else: 147 | return self.getValue(key[1:],root.next[root.next.index(node)]) 148 | return None 149 | 150 | if __name__ == '__main__': 151 | 152 | t = Trie() 153 | 154 | t.add('bob',1) 155 | 156 | t.add('bad',2) 157 | t.add('ba',5) 158 | t.add('bat',3) 159 | t.add('banner',4) 160 | t.add('banno',4) 161 | t.add('add',3) 162 | t.add('apple',4) 163 | t.add('at',5) 164 | t.add('ate',6) 165 | 166 | print(t) 167 | deleteMe = 'ate' 168 | t.remove(deleteMe) 169 | print("\nAfter delete '%s':\n%s"%(deleteMe, t)) 170 | 171 | print() 172 | 173 | print("ADDED?%s"%t.add('bob',2)) 174 | 175 | print(t) 176 | -------------------------------------------------------------------------------- /Trees/Trie_Prefix_Count.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 3/3/2013 4 | 5 | #Trie is built using a Tree-like structure 6 | #Each node contains a single character and number of times prefix added 7 | #Each word can be created by going from the root down any branch to a 8 | # terminating node or a node where the value of the parent node is greater 9 | # than the sum of the values of the children nodes 10 | #The traversePrefixes method goes through each branch and strings together 11 | # all prefixes 12 | 13 | from ADTs.Queue_head import Queue 14 | from ADTs.Stack import Stack 15 | 16 | class Node: 17 | def __init__(self,key): 18 | self.key = key 19 | self.value = 1 20 | self.next = [] 21 | 22 | class Trie: 23 | def __init__(self): 24 | self.root = Node(None) 25 | self.output = '' 26 | 27 | def __str__(self): 28 | string = "BFS: %s"%str(self.traverseBFS()) 29 | string += "\nPrefixes: %s"%str(self.traversePrefixes()) 30 | return string 31 | 32 | def traversePrefixes(self): 33 | self.output = '' 34 | if not self.root.next: 35 | self.output = 'Empty' 36 | for child in self.root.next: 37 | self.output += child.key + (" (%s), "%child.value) 38 | self.traverse(child,'') 39 | return self.output.rstrip(', ') 40 | 41 | def traverse(self,root,prefix): 42 | prefix += root.key 43 | for node in root.next: 44 | self.output += prefix + node.key + (" (%s), "%node.value) 45 | if node.next and node.value: 46 | self.traverse(node,prefix) 47 | 48 | def traverseBFS(self): 49 | keys = [] 50 | bfsQ = Queue() 51 | bfsQ.enQueue(self.root) 52 | cur = bfsQ.deQueue() 53 | while cur: 54 | if(cur != self.root): 55 | keys.append(cur.key) 56 | for node in cur.next: 57 | bfsQ.enQueue(node) 58 | cur = bfsQ.deQueue() 59 | return ', '.join([str(key) for key in keys]) 60 | 61 | #IF key already exists, it just updates the counts 62 | def add(self, key, root=None): 63 | if not type(key) == str: 64 | return False 65 | if not key: 66 | return True 67 | if not root: 68 | root = self.root 69 | for node in root.next: 70 | if key[0] in node.key: 71 | node.value +=1 72 | return self.add(key[1:],root.next[root.next.index(node)]) 73 | root.next.append(Node(key[0])) 74 | return self.add(key[1:],root.next[-1]) 75 | 76 | def remove(self, key): 77 | if not self.isMember(key, self.root): 78 | return False 79 | return self.removeHelper(key, self.root,0) 80 | 81 | def removeHelper(self,key,root,index): 82 | for node in root.next: 83 | if key[index] in node.key: 84 | #No next neighbors and value is 1 85 | #Delete the element completely and recurse back and test previous index 86 | #Already Know it is a member so can do this without checking length 87 | if not node.next and node.value == 1: 88 | del root.next[root.next.index(node)] 89 | self.removeHelper(key,root,index-1) 90 | #Last element in key with a next neighbor and the value is > 1 91 | #We don't have to worry about value issues since isMember is checked first 92 | #Decrement the value and recurse back through the previous nodes 93 | elif index == len(key)-1 and node.next and node.value > 1: 94 | node.value -= 1 95 | return True 96 | else: 97 | #Not the last key and there is a next neighbor, recurse further 98 | self.removeHelper(key,node,index+1) 99 | #This runs after the last element is deleted or decremented 100 | #It checks earlier nodes to see if they also need deleted and 101 | # if not then decrement 102 | if not node.next and node.value == 1: 103 | del root.next[root.next.index(node)] 104 | else: 105 | node.value -=1 106 | return True 107 | return False 108 | 109 | def isMember(self, key, root=None): 110 | if not type(key) == str or not key: 111 | return False 112 | if not root: 113 | root = self.root 114 | for node in root.next: 115 | if key[0] in node.key: 116 | if len(key) == 1 and not node.next: 117 | return True 118 | else: 119 | #This 'IF' checks to make sure we don't determine a prefix 120 | # that hasn't been individually added to be a member 121 | #Example if we add 'ate', we say 'at' is not a member unless 122 | # we specifically add 'at' 123 | #This ensures that we can't remove all of the prefixes for a 124 | # word such as add 'ate' but then remove 'at' from it leaving 125 | # a dangling 'e' 126 | if len(key) == 1: 127 | suffixCount = 0 128 | for child in node.next: 129 | suffixCount += child.value 130 | #It is a member only if the value for that node is greater than 131 | # the sum of it's children 132 | #Ex: we add 'ate' and 'at'. The value for 'at' is 2, 'ate' is 1, so we 133 | # can safely remove only 1 'at' 134 | if node.value > suffixCount: 135 | return True 136 | else: 137 | return False 138 | return self.isMember(key[1:],root.next[root.next.index(node)]) 139 | return False 140 | 141 | def getValue(self,key,root=None): 142 | if not type(key) == str or not key: 143 | return None 144 | if not root: 145 | root = self.root 146 | for node in root.next: 147 | if key[0] in node.key: 148 | if len(key) == 1 and node.value: 149 | return node.value 150 | else: 151 | return self.getValue(key[1:],root.next[root.next.index(node)]) 152 | return None 153 | 154 | if __name__ == '__main__': 155 | 156 | t = Trie() 157 | 158 | t.add('bob') 159 | 160 | t.add('bad') 161 | t.add('bad') 162 | t.add('ba') 163 | t.add('bat') 164 | 165 | 166 | print(t) 167 | deleteMe = 'ba' 168 | if(t.remove(deleteMe)): 169 | print("\nAfter delete '%s':\n%s"%(deleteMe, t)) 170 | 171 | deleteMe = 'ba' 172 | if(t.remove(deleteMe)): 173 | print("\nAfter delete '%s':\n%s"%(deleteMe, t)) 174 | else: 175 | print("\nDelete '%s' Failed:\n%s"%(deleteMe, t)) 176 | 177 | deleteMe = 'ba' 178 | if(t.remove(deleteMe)): 179 | print("\nAfter delete '%s':\n%s"%(deleteMe, t)) 180 | else: 181 | print("\nDelete '%s' Failed:\n%s"%(deleteMe, t)) 182 | -------------------------------------------------------------------------------- /Trees/Trie_Prefix_Count_Speed.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 3/4/2013 4 | 5 | #Trie is built using a Tree-like structure 6 | #Each node contains a single character and number of times prefix added 7 | #Each word can be created by going from the root down any branch to a 8 | # terminating node or a node where the value of the parent node is greater 9 | # than the sum of the values of the children nodes 10 | #The traversePrefixes method goes through each branch and strings together 11 | # all prefixes 12 | 13 | from ADTs.Queue_head import Queue 14 | from ADTs.Stack import Stack 15 | 16 | class Node: 17 | def __init__(self,key): 18 | self.key = key 19 | self.value = 1 20 | self.next = [None for x in range(0,95)] 21 | 22 | class Trie: 23 | def __init__(self): 24 | self.root = Node(None) 25 | self.output = '' 26 | 27 | def __str__(self): 28 | string = "BFS: %s"%str(self.traverseBFS()) 29 | string += "\nPrefixes: %s"%str(self.traversePrefixes()) 30 | return string 31 | 32 | def traversePrefixes(self): 33 | self.output = '' 34 | for child in self.root.next: 35 | if child!=None: 36 | self.output += child.key + (" (%s), "%child.value) 37 | self.traverse(child,'') 38 | if self.output == '': 39 | self.output = 'Empty' 40 | return self.output.rstrip(', ') 41 | 42 | def traverse(self,root,prefix): 43 | prefix += root.key 44 | for node in root.next: 45 | if node!=None: 46 | self.output += prefix + node.key + (" (%s), "%node.value) 47 | if node.next and node.value: 48 | self.traverse(node,prefix) 49 | 50 | def traverseBFS(self): 51 | keys = [] 52 | bfsQ = Queue() 53 | bfsQ.enQueue(self.root) 54 | cur = bfsQ.deQueue() 55 | while cur: 56 | if(cur != self.root): 57 | keys.append(cur.key) 58 | for node in cur.next: 59 | if node !=None: 60 | bfsQ.enQueue(node) 61 | cur = bfsQ.deQueue() 62 | return ', '.join([str(key) for key in keys]) 63 | 64 | #IF key already exists, it just updates the counts 65 | def add(self, key, root=None): 66 | if not type(key) == str: 67 | return False 68 | if not key: 69 | return True 70 | if not root: 71 | root = self.root 72 | index = ord(key[0])-32 73 | if root.next[index] != None: 74 | root.next[index].value +=1 75 | else: 76 | root.next[index] = Node(key[0]) 77 | return self.add(key[1:],root.next[index]) 78 | 79 | def remove(self, key): 80 | if not self.isMember(key, self.root): 81 | return False 82 | return self.removeHelper(key, self.root,0) 83 | 84 | def removeHelper(self,key,root,keyIndex): 85 | index = ord(key[keyIndex])-32 86 | if root.next[index] != None: 87 | #No next neighbors and value is 1 88 | #Clear the element completely and recurse back and test previous index 89 | #Already Know it is a member so can do this without checking length 90 | children = False 91 | for child in root.next[index].next: 92 | if child != None: 93 | children = True 94 | break 95 | if not children and root.next[index].value == 1: 96 | root.next[index] = None 97 | self.removeHelper(key,root,keyIndex-1) 98 | #Last element in key with a next neighbor and the value is > 1 99 | #We don't have to worry about value issues since isMember is checked first 100 | #Decrement the value and recurse back through the previous nodes 101 | elif keyIndex == len(key)-1 and children and root.next[index].value > 1: 102 | root.next[index].value -= 1 103 | return True 104 | else: 105 | #Not the last key and there is a next neighbor, recurse further 106 | self.removeHelper(key,root.next[index],keyIndex+1) 107 | #This runs after the last element is deleted or decremented 108 | #It checks earlier nodes to see if they also need deleted and 109 | # if not then decrement 110 | children = False 111 | for child in root.next[index].next: 112 | if child != None: 113 | children = True 114 | break 115 | if not children and root.next[index].value == 1: 116 | root.next[index] = None 117 | else: 118 | root.next[index].value -=1 119 | return True 120 | return False 121 | 122 | def isMember(self, key, root=None): 123 | if not type(key) == str or not key: 124 | return False 125 | if not root: 126 | root = self.root 127 | index = ord(key[0])-32 128 | if root.next[index] != None: 129 | #This 'IF' checks to make sure we don't determine a prefix 130 | # that hasn't been individually added to be a member 131 | #Example if we add 'ate', we say 'at' is not a member unless 132 | # we specifically add 'at' 133 | #This ensures that we can't remove all of the prefixes for a 134 | # word such as add 'ate' but then remove 'at' from it leaving 135 | # a dangling 'e' 136 | if len(key) == 1: 137 | suffixCount = 0 138 | for child in root.next[index].next: 139 | if child!=None: 140 | suffixCount += child.value 141 | #It is a member only if the value for that node is greater than 142 | # the sum of it's children 143 | #Ex: we add 'ate' and 'at'. The value for 'at' is 2, 'ate' is 1, so we 144 | # can safely remove only 1 'at' 145 | if root.next[index].value > suffixCount: 146 | return True 147 | else: 148 | return False 149 | return self.isMember(key[1:],root.next[index]) 150 | return False 151 | 152 | def getValue(self,key,root=None): 153 | if not type(key) == str or not key: 154 | return None 155 | if not root: 156 | root = self.root 157 | index = ord(key[0])-32 158 | if root.next[index] != None: 159 | if len(key) == 1 and root.next[index].value: 160 | return root.next[index].value 161 | else: 162 | return self.getValue(key[1:],root.next[index]) 163 | return None 164 | 165 | if __name__ == '__main__': 166 | 167 | t = Trie() 168 | 169 | t.add('bob') 170 | 171 | t.add('bad') 172 | t.add('bad') 173 | t.add('ba') 174 | t.add('bat') 175 | 176 | 177 | print(t) 178 | deleteMe = 'ba' 179 | if(t.remove(deleteMe)): 180 | print("\nAfter delete '%s':\n%s"%(deleteMe, t)) 181 | 182 | deleteMe = 'ba' 183 | if(t.remove(deleteMe)): 184 | print("\nAfter delete '%s':\n%s"%(deleteMe, t)) 185 | else: 186 | print("\nDelete '%s' Failed:\n%s"%(deleteMe, t)) 187 | 188 | deleteMe = 'ba' 189 | if(t.remove(deleteMe)): 190 | print("\nAfter delete '%s':\n%s"%(deleteMe, t)) 191 | else: 192 | print("\nDelete '%s' Failed:\n%s"%(deleteMe, t)) 193 | -------------------------------------------------------------------------------- /Trees/Trie_Prefix_Count_Speed_UnitTests.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 3/4/2013 4 | 5 | from Trie_Prefix_Count_Speed import Trie 6 | import unittest 7 | 8 | class TestPrefixTrie(unittest.TestCase): 9 | 10 | def setUp(self): 11 | self.empty = Trie() 12 | self.t = Trie() 13 | 14 | self.t.add('bob') 15 | self.t.add('apple') 16 | 17 | def testEmpty(self): 18 | words = self.empty.traversePrefixes() 19 | 20 | self.assertEqual(words,'Empty') 21 | 22 | print('\ntestEmpty PASSED') 23 | 24 | def testInsert(self): 25 | self.empty.add('bob') 26 | words = self.empty.traversePrefixes() 27 | self.assertEqual(words,'b (1), bo (1), bob (1)') 28 | 29 | self.empty.add('apple') 30 | words = self.empty.traversePrefixes() 31 | self.assertEqual(words,'a (1), ap (1), app (1), appl (1), apple (1), ' \ 32 | 'b (1), bo (1), bob (1)') 33 | 34 | print('\ntestInsert PASSED') 35 | 36 | def testIsMember(self): 37 | result = self.t.isMember('bob') and self.t.isMember('apple') 38 | self.assertTrue(result) 39 | 40 | result = self.t.isMember('bab') or self.t.isMember('bobo') or \ 41 | self.t.isMember('apples') or self.t.isMember('dave') 42 | self.assertFalse(result) 43 | 44 | print('\ntestIsMember PASSED') 45 | 46 | def testCommonPrefix(self): 47 | self.t.add('at') 48 | words = self.t.traversePrefixes() 49 | self.assertEqual(words,'a (2), ap (1), app (1), appl (1), apple (1), at (1), '\ 50 | 'b (1), bo (1), bob (1)') 51 | result = self.t.getValue('at') 52 | self.assertEqual(result, 1) 53 | result = self.t.isMember('at') 54 | self.assertTrue(result) 55 | 56 | self.t.add('ate') 57 | result = self.t.getValue('ate') 58 | self.assertEqual(result, 1) 59 | result = self.t.isMember('ate') 60 | self.assertTrue(result) 61 | 62 | result = self.t.getValue('at') 63 | self.assertEqual(result, 2) 64 | result = self.t.isMember('at') 65 | self.assertTrue(result) 66 | 67 | words = self.t.traversePrefixes() 68 | self.assertEqual(words,'a (3), ap (1), app (1), appl (1), apple (1), at (2), ate (1), '\ 69 | 'b (1), bo (1), bob (1)') 70 | 71 | self.t.remove('at') 72 | words = self.t.traversePrefixes() 73 | self.assertEqual(words,'a (2), ap (1), app (1), appl (1), apple (1), at (1), ate (1), '\ 74 | 'b (1), bo (1), bob (1)') 75 | 76 | result = self.t.isMember('at') 77 | self.assertFalse(result) 78 | self.assertEqual(self.t.getValue('at'),1) 79 | 80 | result = self.t.isMember('ate') 81 | self.assertTrue(result) 82 | self.assertEqual(self.t.getValue('ate'),1) 83 | 84 | self.t.add('at') 85 | result = self.t.getValue('at') 86 | self.assertEqual(result, 2) 87 | result = self.t.isMember('at') 88 | self.assertTrue(result) 89 | 90 | words = self.t.traversePrefixes() 91 | self.assertEqual(words,'a (3), ap (1), app (1), appl (1), apple (1), at (2), ate (1), '\ 92 | 'b (1), bo (1), bob (1)') 93 | 94 | self.t.remove('ate') 95 | words = self.t.traversePrefixes() 96 | self.assertEqual(words,'a (2), ap (1), app (1), appl (1), apple (1), at (1), '\ 97 | 'b (1), bo (1), bob (1)') 98 | 99 | result = self.t.isMember('at') 100 | self.assertTrue(result) 101 | self.assertEqual(self.t.getValue('at'),1) 102 | 103 | result = self.t.isMember('ate') 104 | self.assertFalse(result) 105 | self.assertEqual(self.t.getValue('ate'),None) 106 | 107 | print('\ntestCommonPrefix PASSED') 108 | 109 | def testRemove(self): 110 | self.t.add('add') 111 | result = self.t.isMember('add') 112 | self.assertTrue(result) 113 | 114 | result = self.t.traversePrefixes() 115 | self.assertEqual(result, 'a (2), ad (1), add (1), ap (1), app (1), appl (1), apple (1), '\ 116 | 'b (1), bo (1), bob (1)') 117 | 118 | boolResult = self.t.remove('apple') 119 | self.assertTrue(boolResult) 120 | result = self.t.traversePrefixes() 121 | self.assertEqual(result, 'a (1), ad (1), add (1), b (1), bo (1), bob (1)') 122 | 123 | boolResult = self.t.remove('add') 124 | self.assertTrue(boolResult) 125 | result = self.t.traversePrefixes() 126 | self.assertEqual(result, 'b (1), bo (1), bob (1)') 127 | 128 | boolResult = self.t.remove('bob') 129 | self.assertTrue(boolResult) 130 | result = self.t.traversePrefixes() 131 | self.assertEqual(result, 'Empty') 132 | 133 | print('\ntestRemove PASSED') 134 | 135 | def testGetValue(self): 136 | result = self.t.getValue('bob') 137 | self.assertEqual(result, 1) 138 | 139 | result = self.t.getValue('apple') 140 | self.assertEqual(result, 1) 141 | 142 | result = self.t.getValue('bo') 143 | self.assertEqual(result, 1) 144 | 145 | result = self.t.getValue('dave') 146 | self.assertEqual(result, None) 147 | 148 | print('\ntestGetValue PASSED') 149 | 150 | if __name__ == '__main__': 151 | unittest.main() -------------------------------------------------------------------------------- /Trees/Trie_Prefix_Count_UnitTests.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 3/3/2013 4 | 5 | from Trie_Prefix_Count import Trie 6 | import unittest 7 | 8 | class TestPrefixTrie(unittest.TestCase): 9 | 10 | def setUp(self): 11 | self.empty = Trie() 12 | self.t = Trie() 13 | 14 | self.t.add('bob') 15 | self.t.add('apple') 16 | 17 | def testEmpty(self): 18 | words = self.empty.traversePrefixes() 19 | 20 | self.assertEqual(words,'Empty') 21 | 22 | print('\ntestEmpty PASSED') 23 | 24 | def testInsert(self): 25 | self.empty.add('bob') 26 | words = self.empty.traversePrefixes() 27 | self.assertEqual(words,'b (1), bo (1), bob (1)') 28 | 29 | self.empty.add('apple') 30 | words = self.empty.traversePrefixes() 31 | self.assertEqual(words,'b (1), bo (1), bob (1), a (1), ap (1), app (1), '\ 32 | 'appl (1), apple (1)') 33 | 34 | print('\ntestInsert PASSED') 35 | 36 | def testIsMember(self): 37 | result = self.t.isMember('bob') and self.t.isMember('apple') 38 | self.assertTrue(result) 39 | 40 | result = self.t.isMember('bab') or self.t.isMember('bobo') or \ 41 | self.t.isMember('apples') or self.t.isMember('dave') 42 | self.assertFalse(result) 43 | 44 | print('\ntestIsMember PASSED') 45 | 46 | def testCommonPrefix(self): 47 | self.t.add('at') 48 | words = self.t.traversePrefixes() 49 | self.assertEqual(words,'b (1), bo (1), bob (1), a (2), ap (1), app (1), appl (1), '\ 50 | 'apple (1), at (1)') 51 | result = self.t.getValue('at') 52 | self.assertEqual(result, 1) 53 | result = self.t.isMember('at') 54 | self.assertTrue(result) 55 | 56 | self.t.add('ate') 57 | result = self.t.getValue('ate') 58 | self.assertEqual(result, 1) 59 | result = self.t.isMember('ate') 60 | self.assertTrue(result) 61 | 62 | result = self.t.getValue('at') 63 | self.assertEqual(result, 2) 64 | result = self.t.isMember('at') 65 | self.assertTrue(result) 66 | 67 | words = self.t.traversePrefixes() 68 | self.assertEqual(words,'b (1), bo (1), bob (1), a (3), ap (1), app (1), appl (1), '\ 69 | 'apple (1), at (2), ate (1)') 70 | 71 | self.t.remove('at') 72 | words = self.t.traversePrefixes() 73 | self.assertEqual(words,'b (1), bo (1), bob (1), a (2), ap (1), app (1), appl (1), '\ 74 | 'apple (1), at (1), ate (1)') 75 | 76 | result = self.t.isMember('at') 77 | self.assertFalse(result) 78 | self.assertEqual(self.t.getValue('at'),1) 79 | 80 | result = self.t.isMember('ate') 81 | self.assertTrue(result) 82 | self.assertEqual(self.t.getValue('ate'),1) 83 | 84 | self.t.add('at') 85 | result = self.t.getValue('at') 86 | self.assertEqual(result, 2) 87 | result = self.t.isMember('at') 88 | self.assertTrue(result) 89 | 90 | words = self.t.traversePrefixes() 91 | self.assertEqual(words,'b (1), bo (1), bob (1), a (3), ap (1), app (1), appl (1), '\ 92 | 'apple (1), at (2), ate (1)') 93 | 94 | self.t.remove('ate') 95 | words = self.t.traversePrefixes() 96 | self.assertEqual(words,'b (1), bo (1), bob (1), a (2), ap (1), app (1), appl (1), '\ 97 | 'apple (1), at (1)') 98 | 99 | result = self.t.isMember('at') 100 | self.assertTrue(result) 101 | self.assertEqual(self.t.getValue('at'),1) 102 | 103 | result = self.t.isMember('ate') 104 | self.assertFalse(result) 105 | self.assertEqual(self.t.getValue('ate'),None) 106 | 107 | print('\ntestCommonPrefix PASSED') 108 | 109 | def testRemove(self): 110 | self.t.add('add') 111 | result = self.t.isMember('add') 112 | self.assertTrue(result) 113 | 114 | result = self.t.traversePrefixes() 115 | self.assertEqual(result, 'b (1), bo (1), bob (1), a (2), ap (1), app (1), appl (1), '\ 116 | 'apple (1), ad (1), add (1)') 117 | 118 | boolResult = self.t.remove('apple') 119 | self.assertTrue(boolResult) 120 | result = self.t.traversePrefixes() 121 | self.assertEqual(result, 'b (1), bo (1), bob (1), a (1), ad (1), add (1)') 122 | 123 | boolResult = self.t.remove('add') 124 | self.assertTrue(boolResult) 125 | result = self.t.traversePrefixes() 126 | self.assertEqual(result, 'b (1), bo (1), bob (1)') 127 | 128 | boolResult = self.t.remove('bob') 129 | self.assertTrue(boolResult) 130 | result = self.t.traversePrefixes() 131 | self.assertEqual(result, 'Empty') 132 | 133 | print('\ntestRemove PASSED') 134 | 135 | def testGetValue(self): 136 | result = self.t.getValue('bob') 137 | self.assertEqual(result, 1) 138 | 139 | result = self.t.getValue('apple') 140 | self.assertEqual(result, 1) 141 | 142 | result = self.t.getValue('bo') 143 | self.assertEqual(result, 1) 144 | 145 | result = self.t.getValue('dave') 146 | self.assertEqual(result, None) 147 | 148 | print('\ntestGetValue PASSED') 149 | 150 | if __name__ == '__main__': 151 | unittest.main() -------------------------------------------------------------------------------- /Trees/Trie_Time_Tester.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 3/5/2013 4 | 5 | import time 6 | from Trie_Prefix_Count import Trie as Trie_space 7 | from Trie_Prefix_Count_Speed import Trie as Trie_speed 8 | 9 | t = Trie_space() 10 | 11 | start = time.clock() 12 | print('Start Trie Space: %s'%start) 13 | 14 | fileIn = open('../Lorem_ipsum.txt','r').read() 15 | words = fileIn.split(' ') 16 | 17 | for word in words: 18 | t.add(word) 19 | 20 | wordTime = time.clock() 21 | print('Words added in: %f'%(wordTime-start)) 22 | 23 | wordFindTime = time.clock() 24 | print('Found pellentesque value = %s in %f'%(t.getValue('pellentesque'),(wordFindTime - wordTime))) 25 | 26 | t = Trie_speed() 27 | start = time.clock() 28 | print('Start Trie Speed: %f'%start) 29 | 30 | fileIn = open('../Lorem_ipsum.txt','r').read() 31 | words = fileIn.split(' ') 32 | 33 | for word in words: 34 | t.add(word) 35 | 36 | wordTime = time.clock() 37 | print('Words added in: %f'%(wordTime-start)) 38 | 39 | wordFindTime = time.clock() 40 | print('Found pellentesque value = %s in %f'%(t.getValue('pellentesque'),(wordFindTime - wordTime))) -------------------------------------------------------------------------------- /Trees/Trie_UnitTests.py: -------------------------------------------------------------------------------- 1 | #Michael Robertson 2 | #mirob2005@gmail.com 3 | #Completed: 3/3/2013 4 | 5 | from Trie import Trie 6 | import unittest 7 | 8 | class TestTrie(unittest.TestCase): 9 | 10 | def setUp(self): 11 | self.empty = Trie() 12 | self.t = Trie() 13 | 14 | self.t.add('bob',2) 15 | self.t.add('apple', 3) 16 | 17 | def testEmpty(self): 18 | words = self.empty.traverseWords() 19 | 20 | self.assertEqual(words,'Empty') 21 | 22 | print('\ntestEmpty PASSED') 23 | 24 | def testInsert(self): 25 | self.empty.add('bob',2) 26 | words = self.empty.traverseWords() 27 | self.assertEqual(words,'bob') 28 | 29 | self.empty.add('apple', 3) 30 | words = self.empty.traverseWords() 31 | self.assertEqual(words,'bob apple') 32 | 33 | print('\ntestInsert PASSED') 34 | 35 | def testIsMember(self): 36 | result = self.t.isMember('bob') and self.t.isMember('apple') 37 | self.assertTrue(result) 38 | 39 | result = self.t.isMember('bo') or self.t.isMember('bobo') or self.t.isMember('ap') or \ 40 | self.t.isMember('dave') 41 | self.assertFalse(result) 42 | 43 | print('\ntestIsMember PASSED') 44 | 45 | def testCommonPrefix(self): 46 | self.t.add('at',5) 47 | words = self.t.traverseWords() 48 | self.assertEqual(words,'bob apple at') 49 | result = self.t.getValue('at') 50 | self.assertEqual(result, 5) 51 | result = self.t.isMember('at') 52 | self.assertTrue(result) 53 | 54 | self.t.add('ate',7) 55 | result = self.t.getValue('ate') 56 | self.assertEqual(result, 7) 57 | result = self.t.isMember('ate') 58 | self.assertTrue(result) 59 | 60 | result = self.t.getValue('at') 61 | self.assertEqual(result, 5) 62 | result = self.t.isMember('at') 63 | self.assertTrue(result) 64 | 65 | words = self.t.traverseWords() 66 | self.assertEqual(words,'bob apple at ate') 67 | 68 | self.t.remove('at') 69 | words = self.t.traverseWords() 70 | self.assertEqual(words,'bob apple ate') 71 | 72 | result = self.t.isMember('at') 73 | self.assertFalse(result) 74 | self.assertEqual(self.t.getValue('at'),None) 75 | 76 | result = self.t.isMember('ate') 77 | self.assertTrue(result) 78 | self.assertEqual(self.t.getValue('ate'),7) 79 | 80 | self.t.add('at',6) 81 | result = self.t.getValue('at') 82 | self.assertEqual(result, 6) 83 | result = self.t.isMember('at') 84 | self.assertTrue(result) 85 | 86 | words = self.t.traverseWords() 87 | self.assertEqual(words,'bob apple at ate') 88 | 89 | self.t.remove('ate') 90 | words = self.t.traverseWords() 91 | self.assertEqual(words,'bob apple at') 92 | 93 | result = self.t.isMember('at') 94 | self.assertTrue(result) 95 | self.assertEqual(self.t.getValue('at'),6) 96 | 97 | result = self.t.isMember('ate') 98 | self.assertFalse(result) 99 | self.assertEqual(self.t.getValue('ate'),None) 100 | 101 | print('\ntestCommonPrefix PASSED') 102 | 103 | def testRemove(self): 104 | self.t.add('add',5) 105 | result = self.t.isMember('add') 106 | self.assertTrue(result) 107 | 108 | result = self.t.traverseWords() 109 | self.assertEqual(result, 'bob apple add') 110 | 111 | boolResult = self.t.remove('apple') 112 | self.assertTrue(boolResult) 113 | result = self.t.traverseWords() 114 | self.assertEqual(result, 'bob add') 115 | 116 | boolResult = self.t.remove('add') 117 | self.assertTrue(boolResult) 118 | result = self.t.traverseWords() 119 | self.assertEqual(result, 'bob') 120 | 121 | boolResult = self.t.remove('bob') 122 | self.assertTrue(boolResult) 123 | result = self.t.traverseWords() 124 | self.assertEqual(result, 'Empty') 125 | 126 | print('\ntestRemove PASSED') 127 | 128 | def testUpdateValue(self): 129 | result = self.t.updateValue('bob',10) 130 | self.assertTrue(result) 131 | checkValue = self.t.getValue('bob') 132 | self.assertEqual(checkValue, 10) 133 | 134 | result = self.t.updateValue('apple',12) 135 | self.assertTrue(result) 136 | checkValue = self.t.getValue('apple') 137 | self.assertEqual(checkValue, 12) 138 | 139 | result = self.t.updateValue('app',1) 140 | self.assertTrue(result) 141 | checkValue = self.t.getValue('app') 142 | self.assertEqual(checkValue, 1) 143 | 144 | result = self.t.updateValue('dave',12) 145 | self.assertFalse(result) 146 | checkValue = self.t.getValue('dave') 147 | self.assertEqual(checkValue, None) 148 | 149 | print('\ntestUpdateValue PASSED') 150 | 151 | def testGetValue(self): 152 | result = self.t.getValue('bob') 153 | self.assertEqual(result, 2) 154 | 155 | result = self.t.getValue('apple') 156 | self.assertEqual(result, 3) 157 | 158 | result = self.t.getValue('bo') 159 | self.assertEqual(result, None) 160 | 161 | result = self.t.getValue('dave') 162 | self.assertEqual(result, None) 163 | 164 | print('\ntestGetValue PASSED') 165 | 166 | if __name__ == '__main__': 167 | unittest.main() -------------------------------------------------------------------------------- /Trees/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirob2005/Python_Data_Structures/2851dc124e9b52391842521e584bf5ce716f3740/Trees/__init__.py -------------------------------------------------------------------------------- /__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mirob2005/Python_Data_Structures/2851dc124e9b52391842521e584bf5ce716f3740/__init__.py --------------------------------------------------------------------------------