├── README.md ├── linked_stack.py ├── doubly_linked_base.py └── main_code.py /README.md: -------------------------------------------------------------------------------- 1 | # "Make Your Own Data Structure to Solve BigInt" Project 2 | My last minute term project with full of to-do's and OOP disasters. 3 | * Write Operator Overload for Direct Support for Operators 4 | * Negative Numbers Support 5 | * Cleaner Tests 6 | * Better OOP design (create "BigInt" as a class inside the LinkedDeque instead) 7 | * Write power operation with nlogn efficiency 8 | -------------------------------------------------------------------------------- /linked_stack.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013, Michael H. Goldwasser 2 | # 3 | # Developed for use with the book: 4 | # 5 | # Data Structures and Algorithms in Python 6 | # Michael T. Goodrich, Roberto Tamassia, and Michael H. Goldwasser 7 | # John Wiley & Sons, 2013 8 | # 9 | # This program is free software: you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation, either version 3 of the License, or 12 | # (at your option) any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | 23 | 24 | class LinkedStack: 25 | """LIFO Stack implementation using a singly linked list for storage.""" 26 | 27 | #-------------------------- nested _Node class -------------------------- 28 | class _Node: 29 | """Lightweight, nonpublic class for storing a singly linked node.""" 30 | __slots__ = '_element', '_next' # streamline memory usage 31 | 32 | def __init__(self, element, next): # initialize node's fields 33 | self._element = element # reference to user's element 34 | self._next = next # reference to next node 35 | 36 | #------------------------------- stack methods ------------------------------- 37 | def __init__(self): 38 | """Create an empty stack.""" 39 | self._head = None # reference to the head node 40 | self._size = 0 # number of stack elements 41 | 42 | def __len__(self): 43 | """Return the number of elements in the stack.""" 44 | return self._size 45 | 46 | def is_empty(self): 47 | """Return True if the stack is empty.""" 48 | return self._size == 0 49 | 50 | def push(self, e): 51 | """Add element e to the top of the stack.""" 52 | self._head = self._Node(e, self._head) # create and link a new node 53 | self._size += 1 54 | 55 | def top(self): 56 | """Return (but do not remove) the element at the top of the stack. 57 | 58 | Raise Empty exception if the stack is empty. 59 | """ 60 | if self.is_empty(): 61 | raise Empty('Stack is empty') 62 | return self._head._element # top of stack is at head of list 63 | 64 | def pop(self): 65 | """Remove and return the element from the top of the stack (i.e., LIFO). 66 | 67 | Raise Empty exception if the stack is empty. 68 | """ 69 | if self.is_empty(): 70 | raise Empty('Stack is empty') 71 | answer = self._head._element 72 | self._head = self._head._next # bypass the former top node 73 | self._size -= 1 74 | return answer 75 | 76 | def find_duplicates(self): 77 | 78 | walk1 = self._head 79 | walk2 = self._head._next 80 | 81 | if self._size < 2: 82 | raise Error("The stack has only one element") 83 | 84 | elif self._size < 1: 85 | raise Error("The stack is empty") 86 | 87 | elif self._size > 1: 88 | while walk1._next is not None and walk2 is not None: 89 | #not checking the last element 90 | print (walk1._element, walk2._element) 91 | 92 | if walk1._element == walk2._element: 93 | print ("Duplicate was found") 94 | 95 | if walk2._next is None: #the inner loop is over 96 | walk1 = walk1._next #update outer loop 97 | walk2 = walk1._next #restart inner loop 98 | elif walk2._next: 99 | walk2 = walk2._next #inner loop continues 100 | 101 | 102 | 103 | if __name__=="__main__": 104 | A = LinkedStack() 105 | A.push(5) 106 | A.push(4) 107 | A.push(3) 108 | A.push(3) 109 | A.push(2) 110 | A.push(1) 111 | A.find_duplicates() 112 | -------------------------------------------------------------------------------- /doubly_linked_base.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013, Michael H. Goldwasser 2 | # 3 | # Developed for use with the book: 4 | # 5 | # Data Structures and Algorithms in Python 6 | # Michael T. Goodrich, Roberto Tamassia, and Michael H. Goldwasser 7 | # John Wiley & Sons, 2013 8 | 9 | class _DoublyLinkedBase: 10 | """A base class providing a doubly linked list representation.""" 11 | 12 | #-------------------------- nested _Node class -------------------------- 13 | # nested _Node class 14 | class _Node: 15 | """Lightweight, nonpublic class for storing a doubly linked node.""" 16 | __slots__ = '_element', '_prev', '_next' # streamline memory 17 | 18 | def __init__(self, element, prev, next): # initialize node's fields 19 | self._element = element # user's element 20 | self._prev = prev # previous node reference 21 | self._next = next # next node reference 22 | 23 | #-------------------------- list constructor -------------------------- 24 | 25 | def __init__(self): 26 | """Create an empty list.""" 27 | self._header = self._Node(None, None, None) 28 | self._trailer = self._Node(None, None, None) 29 | self._header._next = self._trailer # trailer is after header 30 | self._trailer._prev = self._header # header is before trailer 31 | self._size = 0 # number of elements 32 | 33 | #-------------------------- public accessors -------------------------- 34 | 35 | def __len__(self): 36 | """Return the number of elements in the list.""" 37 | return self._size 38 | 39 | def is_empty(self): 40 | """Return True if list is empty.""" 41 | return self._size == 0 42 | 43 | #-------------------------- nonpublic utilities -------------------------- 44 | 45 | def _insert_between(self, e, predecessor, successor): 46 | """Add element e between two existing nodes and return new node.""" 47 | newest = self._Node(e, predecessor, successor) # linked to neighbors 48 | predecessor._next = newest 49 | successor._prev = newest 50 | self._size += 1 51 | return newest 52 | 53 | def _delete_node(self, node): 54 | """Delete nonsentinel node from the list and return its element.""" 55 | predecessor = node._prev 56 | successor = node._next 57 | predecessor._next = successor 58 | successor._prev = predecessor 59 | self._size -= 1 60 | element = node._element # record deleted element 61 | node._prev = node._next = node._element = None # deprecate node 62 | return element # return deleted element 63 | 64 | 65 | 66 | class LinkedStack: 67 | """LIFO Stack implementation using a singly linked list for storage.""" 68 | 69 | #-------------------------- nested _Node class -------------------------- 70 | class _Node: 71 | """Lightweight, nonpublic class for storing a singly linked node.""" 72 | __slots__ = '_element', '_next' # streamline memory usage 73 | 74 | def __init__(self, element, next): # initialize node's fields 75 | self._element = element # reference to user's element 76 | self._next = next # reference to next node 77 | 78 | #------------------------------- stack methods ------------------------------- 79 | def __init__(self): 80 | """Create an empty stack.""" 81 | self._head = None # reference to the head node 82 | self._size = 0 # number of stack elements 83 | 84 | def __len__(self): 85 | """Return the number of elements in the stack.""" 86 | return self._size 87 | 88 | def is_empty(self): 89 | """Return True if the stack is empty.""" 90 | return self._size == 0 91 | 92 | def push(self, e): 93 | """Add element e to the top of the stack.""" 94 | self._head = self._Node(e, self._head) # create and link a new node 95 | self._size += 1 96 | 97 | def top(self): 98 | """Return (but do not remove) the element at the top of the stack. 99 | 100 | Raise Empty exception if the stack is empty. 101 | """ 102 | if self.is_empty(): 103 | raise Empty('Stack is empty') 104 | return self._head._element # top of stack is at head of list 105 | 106 | def pop(self): 107 | """Remove and return the element from the top of the stack (i.e., LIFO). 108 | 109 | Raise Empty exception if the stack is empty. 110 | """ 111 | if self.is_empty(): 112 | raise Empty('Stack is empty') 113 | answer = self._head._element 114 | self._head = self._head._next # bypass the former top node 115 | self._size -= 1 116 | return answer 117 | 118 | def pop_second(self): 119 | """ Removes second element by popping first two elements, keeping the first element somewhere else 120 | pushes the previous head again""" 121 | if self._size == 1: 122 | return Exception("There's only one element in the linked stack") 123 | self._head._next = self._head._next_next 124 | self._size-=1 125 | return second 126 | 127 | def push_second(self, e): 128 | """ Pushes second element by popping the initial head, then popping the second one, 129 | then pushing the initial head back""" 130 | if self._size == 1: 131 | return Exception("There's only one element in the linked stack") 132 | first = self.pop() 133 | self.push(e) 134 | self.push(first) 135 | self._size+=1 136 | return self._head._next._element 137 | 138 | def penultimate(self): 139 | if self.size <2: 140 | raise Error("list must be larger than two") 141 | walk = self._head 142 | while walk._next_next is not None: 143 | walk = walk.next 144 | return walk 145 | 146 | def concatenate_second(self, M): 147 | walk = self._head 148 | while walk._next is not None: 149 | walk = walk._next 150 | walk._next = M._head 151 | M._head = None 152 | return walk 153 | 154 | def find_duplicates(self): 155 | 156 | walk1 = self._head 157 | walk2 = self._head._next 158 | 159 | if self._size < 2: 160 | raise Error("The stack has only one element") 161 | 162 | elif self._size < 1: 163 | raise Error("The stack is empty") 164 | 165 | elif self._size > 1: 166 | while walk1._next is not None and walk2 is not None: 167 | #not checking the last element 168 | print (walk1._element, walk2._element) 169 | 170 | if walk1._element == walk2._element: 171 | print ("Duplicate was found") 172 | 173 | if walk2._next is None: #the inner loop is over 174 | walk1 = walk1._next #update outer loop 175 | walk2 = walk1._next #restart inner loop 176 | elif walk2._next: 177 | walk2 = walk2._next #inner loop continues 178 | 179 | 180 | 181 | if __name__=="__main__": 182 | A = LinkedStack() 183 | A.push(5) 184 | A.push(4) 185 | A.push(3) 186 | A.push(3) 187 | A.push(2) 188 | A.push(1) 189 | A.find_duplicates() -------------------------------------------------------------------------------- /main_code.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013, Michael H. Goldwasser 2 | # 3 | # Developed for use with the book: 4 | # 5 | # Data Structures and Algorithms in Python 6 | # Michael T. Goodrich, Roberto Tamassia, and Michael H. Goldwasser 7 | # John Wiley & Sons, 2013 8 | 9 | from doubly_linked_base import _DoublyLinkedBase 10 | 11 | from linked_stack import * 12 | 13 | 14 | class LinkedDeque(_DoublyLinkedBase): # note the use of inheritance 15 | """Double-ended queue implementation based on a doubly linked list.""" 16 | 17 | def first(self): 18 | """Return (but do not remove) the element at the front of the deque. 19 | Raise Empty exception if the deque is empty. 20 | """ 21 | if self.is_empty(): 22 | raise Error("Deque is empty") 23 | return self._header._next._element # real item just after header 24 | 25 | 26 | 27 | def last(self): 28 | """Return (but do not remove) the element at the back of the deque. 29 | Raise Empty exception if the deque is empty. """ 30 | if self.is_empty(): 31 | raise Error("Deque is empty") 32 | return self._trailer._prev._element # real item just before trailer 33 | 34 | 35 | 36 | def insert_first(self, e): 37 | """Add an element to the front of the deque.""" 38 | self._insert_between(e, self._header, self._header._next) # after header 39 | 40 | 41 | 42 | def insert_last(self, e): 43 | """Add an element to the back of the deque.""" 44 | self._insert_between(e, self._trailer._prev, self._trailer) # before trailer 45 | 46 | 47 | 48 | def delete_first(self): 49 | """Remove and return the element from the front of the deque. 50 | Raise Empty exception if the deque is empty. """ 51 | if self.is_empty(): 52 | raise Error("Deque is empty") 53 | return self._delete_node(self._header._next) # use inherited method 54 | 55 | 56 | 57 | def delete_last(self): 58 | """Remove and return the element from the back of the deque. 59 | Raise Empty exception if the deque is empty.""" 60 | if self.is_empty(): 61 | raise Error("Deque is empty") 62 | return self._delete_node(self._trailer._prev) 63 | 64 | 65 | ######################## Big Int Codes Below ########################## 66 | 67 | 68 | def createBigInt(self, s): 69 | """ takes string input and turns it into deque """ 70 | for item in s: 71 | self.insert_last(item) 72 | return self 73 | 74 | def updateBigInt(self, pos, e): 75 | """ takes bigint (self), index (pos), and element and changes 76 | element on index to element taken """ 77 | walk = self._header._next 78 | i = 0 79 | #import pdb; pdb.set_trace() 80 | while walk._next is not None: 81 | if i == pos: 82 | walk._element = e 83 | i = i + 1 84 | walk = walk._next 85 | return self 86 | 87 | 88 | def equalBigInt(self, s1, s2): 89 | 90 | """ takes two strings, turns them into deque bigints 91 | and compares if they're equal """ 92 | 93 | l1 = LinkedDeque() 94 | l2 = LinkedDeque() 95 | b1 = l1.createBigInt(s = s1) 96 | b2 = l2.createBigInt(s = s2) 97 | 98 | walk1 = b1._header._next 99 | walk2 = b2._header._next 100 | 101 | equal = 1 102 | while walk1._next is not None and walk2._next is not None: 103 | if walk1._element != walk2._element: 104 | equal = 0 105 | walk1 = walk1._next 106 | walk2 = walk2._next 107 | 108 | return equal 109 | 110 | 111 | 112 | def freeBigInt(self): 113 | walk = self._header._next 114 | while walk._next is not None: 115 | self.delete_last() 116 | return self 117 | 118 | 119 | #################### multiply bigint ##################### 120 | 121 | def multiplyBigInt(self, s1, s2): 122 | 123 | """ 1. take two strings, fill the left with zeros, 124 | convert them to Linked Deques 125 | 2. iterate over both in a nested way 126 | 3. multiply each order, keep hand and generate numbers to be summed 127 | 4. sum all the numbers """ 128 | 129 | 130 | length1 = len(s1) 131 | length2 = len(s2) 132 | 133 | if length1 > length2: 134 | s2 = s2.zfill(length1) 135 | elif length2 > length1: 136 | s1 = s1.zfill(length2) 137 | 138 | l1 = LinkedDeque() 139 | l2 = LinkedDeque() 140 | 141 | b1 = l1.createBigInt(s = s1) 142 | b2 = l2.createBigInt(s = s2) 143 | 144 | walk1 = b1._trailer._prev #iteration starts from units digit 145 | walk2 = b2._trailer._prev 146 | 147 | hand = 0 148 | 149 | count_out = 0 #counter of orders of outer loop 150 | 151 | sum_all = 0 152 | 153 | #import pdb;pdb.set_trace() 154 | while walk1._prev is not None: #first number 155 | 156 | count = 0 #this is to keep which order we are on 157 | 158 | gen_num = 0 159 | 160 | hand = 0 161 | 162 | walk2 = b2._trailer._prev 163 | 164 | while walk2._prev is not None: #second number 165 | 166 | product = int(walk2._element) * int(walk1._element) + int(hand) 167 | 168 | hand = product // 10 # 2 as in 21 to save for later 169 | 170 | order = product - hand*10 # 1 as in 21 171 | 172 | gen_num = gen_num + order * (10 ** count) 173 | 174 | count = count + 1 175 | 176 | walk2 = walk2._prev 177 | 178 | if walk2._prev is None: 179 | 180 | gen_num = gen_num + hand * (10 ** len(s1)) 181 | 182 | sum_all = sum_all + gen_num * (10 ** count_out) 183 | 184 | count_out = count_out + 1 185 | 186 | walk1 = walk1._prev 187 | 188 | return sum_all 189 | 190 | 191 | ################## power ############ 192 | 193 | def power(self, s, p): 194 | multiplication = 1 195 | for _ in range(p): 196 | multiplication = self.multiplyBigInt(s, str(multiplication)) 197 | 198 | return multiplication 199 | 200 | 201 | 202 | ################### subtract bigint ###################### 203 | 204 | def substractBigInt(self, s1, s2): 205 | 206 | """ 1. takes two strings 207 | 2. look at their lengths, if one is shorter then pad with 208 | zeros for convenience 209 | 3. turns them into deque 210 | 4. substracts them from each other """ 211 | 212 | # finds lengths, pads with zeros, does nothing if equal 213 | l1 = LinkedDeque() 214 | l2 = LinkedDeque() 215 | result = LinkedDeque() 216 | 217 | length1 = len(s1) 218 | length2 = len(s2) 219 | #import pdb;pdb.set_trace() 220 | if length1 > length2: 221 | 222 | s2 = s2.zfill(length1) 223 | 224 | elif length2 > length1: 225 | 226 | s1 = s1.zfill(length2) 227 | 228 | 229 | b1 = l1.createBigInt(s = s1) 230 | b2 = l2.createBigInt(s = s2) 231 | 232 | 233 | # initialize loops and hand 234 | if int(s1) > int(s2): 235 | walk1 = b1._trailer._prev #iteration starts from units digit 236 | walk2 = b2._trailer._prev 237 | 238 | else: 239 | walk1 = b2._trailer._prev 240 | walk2 = b1._trailer._prev 241 | 242 | hand = 0 243 | 244 | while walk1._prev is not None and walk2._prev is not None: 245 | #import pdb;pdb.set_trace() 246 | 247 | substract_order = int(walk1._element) - int(walk2._element) + hand 248 | 249 | 250 | if substract_order < 0: 251 | 252 | value = int(walk1._element) - int(walk2._element) + 10 253 | 254 | hand = -1 255 | 256 | elif substract_order >= 0: 257 | 258 | value = substract_order 259 | 260 | hand = 0 261 | 262 | result.insert_first(e = value) 263 | 264 | walk1 = walk1._prev 265 | walk2 = walk2._prev 266 | 267 | return result 268 | 269 | 270 | 271 | ################### add bigint ############################# 272 | def addBigInt(self, s1, s2): 273 | 274 | """ 1. takes two strings 275 | 2. look at their lengths, if one is shorter then pad with 276 | zeros for convenience 277 | 3. turns them into deque 278 | 4. sums them up """ 279 | 280 | # finds lengths, pads with zeros, does nothing if equal 281 | 282 | length1 = len(s1) 283 | length2 = len(s2) 284 | 285 | if length1 > length2: 286 | s2 = s2.zfill(length1) 287 | elif length2 > length1: 288 | s1 = s1.zfill(length2) 289 | 290 | 291 | # turns strings into deques 292 | 293 | l1 = LinkedDeque() 294 | l2 = LinkedDeque() 295 | 296 | result = LinkedDeque() 297 | 298 | b1 = l1.createBigInt(s = s1) 299 | b2 = l2.createBigInt(s = s2) 300 | 301 | # initialize loops and hand 302 | 303 | walk1 = b1._trailer._prev #iteration starts from units digit 304 | walk2 = b2._trailer._prev 305 | 306 | hand = 0 307 | 308 | while walk1._prev is not None and walk2._prev is not None: 309 | 310 | sum_order = int(walk1._element) + int(walk2._element) + hand #sums for that order 311 | 312 | if sum_order >= 10: 313 | 314 | value = sum_order % 10 315 | 316 | hand = 1 317 | 318 | elif sum_order < 10: 319 | 320 | value = sum_order 321 | 322 | hand = 0 323 | 324 | result.insert_first(e = value) 325 | 326 | walk1 = walk1._prev 327 | walk2 = walk2._prev 328 | 329 | if hand == 1: 330 | result.insert_first(1) 331 | 332 | return result 333 | 334 | ############## deque bigint into stack for infix-postfix ########## 335 | 336 | def stack_BigInt(self, s): 337 | 338 | # turns bigint deque into stack for operations 339 | 340 | BigInt = self.createBigInt(s) 341 | stack = LinkedStack() 342 | walk = BigInt._header._next 343 | 344 | 345 | while walk._next is not None: 346 | stack.push(e = walk._element) 347 | walk = walk._next 348 | return stack 349 | 350 | 351 | 352 | def infix_to_postfix(self, s): 353 | 354 | BigInt = self.createBigInt(s) 355 | 356 | stack = LinkedStack() 357 | 358 | operators = ['-', '+', '*', '/', '(', ')', '^'] 359 | 360 | prec_list= {'+':1, '-':1, '*':2, '/':2, '^':3} 361 | 362 | output = '' 363 | 364 | def isOperand(item): 365 | if item in "1234567890": 366 | return True 367 | else: 368 | return False 369 | 370 | 371 | def isOperator(item): 372 | if item in "-+*/^": 373 | return True 374 | else: 375 | return False 376 | 377 | postfix = "" 378 | 379 | walk = BigInt._header._next 380 | 381 | #import pdb; pdb.set_trace() 382 | 383 | while walk._next is not None: 384 | 385 | if isOperand(item = walk._element): # check if element is 1234.. 386 | 387 | postfix += walk._element 388 | 389 | elif isOperator(walk._element): # check if element is +-.. 390 | 391 | while True: 392 | 393 | try: 394 | top = stack.top() 395 | except: 396 | pass 397 | 398 | if stack.is_empty() or top == "(": 399 | stack.push(walk._element) 400 | break 401 | 402 | # check precedences between the element 403 | # on top of stack and the current element 404 | else: 405 | item = walk._element 406 | prec = prec_list[item] 407 | prectop = prec_list[top] 408 | 409 | if prec > prectop: 410 | stack.push(walk._element) 411 | break 412 | 413 | 414 | else: 415 | postfix += stack.pop() 416 | 417 | elif walk._element == "(": 418 | stack.push(walk._element) 419 | 420 | elif walk._element == ")": 421 | char = stack.pop() 422 | 423 | while char != "(": 424 | postfix+=char 425 | char=stack.pop() 426 | 427 | walk = walk._next 428 | 429 | 430 | while not stack.is_empty(): 431 | char = stack.pop() 432 | postfix += char 433 | 434 | return postfix 435 | 436 | 437 | ####################### debug ########################## 438 | 439 | def debug(self): 440 | # print("THIS IS DEBUG FUNCTION") 441 | walk = self._header._next 442 | output = "" 443 | while walk._next is not None: 444 | output+=str(walk._element) 445 | walk = walk._next 446 | print(output) 447 | 448 | 449 | 450 | ################### test ########################## 451 | 452 | if __name__=="__main__": 453 | #import pdb;pdb.set_trace() 454 | s = input("Enter the operation:") 455 | try: 456 | splitted = s.split(" ") 457 | if len(splitted) == 3: 458 | s1 = splitted[0] 459 | sign = splitted[1] 460 | s2 = splitted[2] 461 | else: 462 | s1 = splitted[0] 463 | sign = splitted[1] 464 | except: 465 | pass 466 | 467 | ld = LinkedDeque() 468 | 469 | if sign == "-": 470 | result = ld.substractBigInt(s1, s2) 471 | result.debug() 472 | elif sign == "+": 473 | result = ld.addBigInt(s1, s2) 474 | result.debug() 475 | elif sign == "==": 476 | result = ld.equalBigInt(s1, s2) 477 | print(result.debug()) 478 | elif sign == "*": 479 | result = ld.multiplyBigInt(s1, s2) 480 | result.debug() 481 | elif sign == "i2p": 482 | #s3 = "123*(238+3*4)+5" 483 | postfix = ld.infix_to_postfix(s1) 484 | print(postfix) 485 | elif sign == "**": 486 | result = ld.power(s1, s2) 487 | result.debug() 488 | 489 | 490 | #test infix to post fix 491 | #s3 = "123*(238+3*4)+5" 492 | #ld = LinkedDeque() 493 | #postfix = ld.infix_to_postfix(s3) 494 | #print(postfix) 495 | 496 | # check create bigint, freebigint 497 | #bigint = ld.createBigInt(s3) 498 | #bigint.freeBigInt() 499 | #print(bigint.debug()) 500 | 501 | # check update bigint and add bigint 502 | #ld = LinkedDeque() 503 | #print(b1._header._next._element) 504 | #b1 = b1.updateBigInt(pos = 5, e = 5) 505 | #result = ld.addBigInt(s1, s2) 506 | #print(result.debug()) """ 507 | # check equal bigint 508 | #equal = ld.equalBigInt(s1,s2) 509 | #print(equal) 510 | --------------------------------------------------------------------------------