/test/language/unclassified/aux_ph01_splay_dictionary.e
Specman e | 568 lines | 474 code | 29 blank | 65 comment | 44 complexity | 3d74400e49a2c40b4e4b2354f95fb3b8 MD5 | raw file
1-- This file is part of SmartEiffel The GNU Eiffel Compiler Tools and Libraries. 2-- See the Copyright notice at the end of this file. 3-- 4class AUX_PH01_SPLAY_DICTIONARY[E, I -> COMPARABLE] 5 -- 6 -- An associative memory implemented as a splay tree. 7 -- 8 -- Values of type E are stored using keys of type I (which must inherit from 9 -- from COMPARABLE). 10 --inherit 11 -- ANY 12 -- redefine 13 -- is_equal, 14 -- copy 15 -- end 16 17create {ANY} 18 make 19 20feature {ANY} 21 make 22 -- Initialises the tree 23 do 24 count := 0 25 root := Void -- This will be the case initially 26 end 27 28feature {ANY} -- Some queries. 29 count: INTEGER 30 -- The number of elements in the tree. 31 32 is_empty: BOOLEAN 33 -- Is the dictionary empty? 34 do 35 Result := root = Void 36 end 37 38 has (index: I): BOOLEAN 39 -- Returns true if the passed index is contained within the tree. 40 local 41 tmp_node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 42 do 43 if not is_empty then 44 from 45 tmp_node := root 46 until 47 tmp_node = Void or else Result = True 48 loop 49 if index = tmp_node.index then 50 -- Case 1. The indexes are the same. Therefore the Result 51 -- is True and we bail. 52 splay(tmp_node) 53 Result := True 54 elseif index < tmp_node.index then 55 -- Case 2. The passed index is lower than the current 56 -- node's index. We simply go left and, if we're 57 -- not pointing at Void, splay the node to the 58 -- top. 59 if tmp_node.left /= Void then 60 tmp_node := tmp_node.left 61 else 62 tmp_node := Void 63 end 64 else 65 -- Case 3. The passed index is larger than the current 66 -- node's index. We simply go right and, if we're 67 -- not pointing at Void, splay the node to the 68 -- top. 69 if tmp_node.right /= Void then 70 tmp_node := tmp_node.right 71 else 72 tmp_node := Void 73 end 74 end 75 end 76 end 77 end 78 79 lowest: I 80 -- Returns the lowest index in the tree. 81 require 82 dictionary_not_empty: not is_empty 83 local 84 tmp_node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 85 do 86 from 87 tmp_node := root 88 until 89 tmp_node.left = Void 90 loop 91 tmp_node := tmp_node.left 92 end 93 splay(tmp_node) 94 Result := tmp_node.index 95 end 96 97 highest: I 98 -- Returns the highest index in the tree. 99 require 100 dictionary_not_empty: not is_empty 101 local 102 tmp_node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 103 do 104 from 105 tmp_node := root 106 until 107 tmp_node.right = Void 108 loop 109 tmp_node := tmp_node.right 110 end 111 splay(tmp_node) 112 Result := tmp_node.index 113 end 114 115feature {ANY} 116 -- The following functions/procedures retrieve function point values or 117 -- information concerning them. 118 item, infix "@" (index: I): E 119 -- Returns the value at the passed index. 120 require 121 has_index: has(index) 122 local 123 chk: BOOLEAN 124 do 125 -- I call `has' first even though it's in the precondition because 126 -- there's not guarantee it'll be called (obviously). Calling this 127 -- ensures that the required node is at the root. 128 chk := has(index) 129 Result := root.item 130 end 131 132feature {ANY} 133 new_iterator: AUX_PH01_SPLAY_DICTIONARY_ITERATOR[I] 134 -- Returns a new iterator for the dictionary. 135 require 136 not_empty: not is_empty 137 do 138 create Result.make(Void) 139 ensure 140 result_not_void: Result /= Void 141 end 142 143feature {ANY} 144 put (value: E; index: I) 145 require 146 item_not_there: not has(index) 147 local 148 elem: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I]; tmp: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 149 do 150 create elem.make(value, index, Void, Void, Void) 151 if is_empty then 152 root := elem 153 count := count + 1 154 else 155 from 156 tmp := root 157 until 158 tmp = Void and then root /= Void 159 loop 160 check 161 elem.index /= tmp.index 162 end 163 if elem.index < tmp.index then 164 if tmp.left = Void then 165 tmp.set_left(elem) 166 elem.set_parent(tmp) 167 splay(elem) 168 count := count + 1 169 tmp := Void 170 else 171 tmp := tmp.left 172 end 173 else 174 if tmp.right = Void then 175 tmp.set_right(elem) 176 elem.set_parent(tmp) 177 splay(elem) 178 count := count + 1 179 tmp := Void 180 else 181 tmp := tmp.right 182 end 183 end 184 end 185 end 186 ensure 187 count_has_incremented: count = old count + 1 188 end 189 190 replace (value: E; index: I) 191 require 192 has_index: has(index) 193 do 194 if has(index) then 195 if index = root.index then 196 root.set_item(value) 197 end 198 end 199 end 200 201 remove (index: I) 202 require 203 has_index: has(index) 204 local 205 left: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I]; right: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 206 tmp: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 207 do 208 if has(index) then 209 if root.right /= Void and root.left /= Void then 210 left := root.left 211 right := root.right 212 tmp := lowest_node_in_subtree(right) 213 tmp.set_left(left) 214 left.set_parent(tmp) 215 right.set_parent(Void) 216 root := right 217 elseif root.right /= Void then 218 right := root.right 219 right.set_parent(Void) 220 root := right 221 elseif root.left /= Void then 222 left := root.left 223 left.set_parent(Void) 224 root := left 225 else 226 root := Void 227 end 228 count := count - 1 229 end 230 ensure 231 count_updated: count = old count - 1 232 end 233 234 remove_maximum 235 require 236 not_empty: not is_empty 237 local 238 tmp: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I]; left: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 239 do 240 tmp := highest_node_in_subtree(root) 241 left := tmp.left 242 if left /= Void then 243 left.set_parent(Void) 244 root := left 245 else 246 root := Void 247 end 248 count := count - 1 249 ensure 250 count_updated: count = old count - 1 251 end 252 253 remove_minimum 254 require 255 not_empty: not is_empty 256 local 257 tmp: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I]; right: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 258 do 259 tmp := lowest_node_in_subtree(root) 260 right := tmp.right 261 if right /= Void then 262 right.set_parent(Void) 263 root := right 264 else 265 root := Void 266 end 267 count := count - 1 268 ensure 269 count_updated: count = old count - 1 270 end 271 272 clear 273 do 274 from 275 until 276 root = Void 277 loop 278 remove_minimum 279 end 280 end 281 282feature {ANY} 283 print_tree 284 do 285 if root /= Void then 286 print_subtree(root.left) 287 root.index.print_on(std_output) 288 print(" ") 289 root.item.print_on(std_output) 290 print("%N") 291 print_subtree(root.right) 292 end 293 end 294 295feature {AUX_PH01_SPLAY_DICTIONARY_ITERATOR} 296 lowest_node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 297 require 298 not_empty: not is_empty 299 do 300 Result := lowest_node_in_subtree(root) 301 splay(Result) 302 ensure 303 result_not_void: Result /= Void 304 end 305 306 highest_node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 307 require 308 not_empty: not is_empty 309 do 310 Result := highest_node_in_subtree(root) 311 splay(Result) 312 ensure 313 result_not_void: Result /= Void 314 end 315 316 next_highest (node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I]): AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 317 require 318 not_empty: not is_empty 319 do 320 splay(node) 321 if root.right /= Void then 322 Result := lowest_node_in_subtree(root.right) 323 splay(Result) 324 end 325 end 326 327feature {INDEXED_LIST} 328 lowest_node_in_subtree (node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I]): AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 329 require 330 node_not_void: node /= Void 331 local 332 elem: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 333 do 334 from 335 elem := node 336 until 337 elem = Void 338 loop 339 if elem.left = Void then 340 Result := elem 341 elem := Void 342 else 343 elem := elem.left 344 end 345 end 346 ensure 347 result_not_void: Result /= Void 348 end 349 350 highest_node_in_subtree (node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I]): AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 351 require 352 node_not_void: node /= Void 353 local 354 elem: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 355 do 356 from 357 elem := node 358 until 359 elem = Void 360 loop 361 if elem.right = Void then 362 Result := elem 363 elem := Void 364 else 365 elem := elem.right 366 end 367 end 368 ensure 369 result_not_void: Result /= Void 370 end 371 372 print_subtree (node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I]) 373 do 374 if node /= Void then 375 if node.left /= Void then 376 print_subtree(node.left) 377 end 378 node.index.print_on(std_output) 379 print(" ") 380 node.item.print_on(std_output) 381 print("%N") 382 if node.right /= Void then 383 print_subtree(node.right) 384 end 385 end 386 end 387 388feature {} 389 has_tree_integrity: BOOLEAN 390 local 391 tmp_node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 392 do 393 if is_empty then 394 Result := True 395 else 396 from 397 tmp_node := lowest_node_in_subtree(root) 398 Result := True 399 until 400 tmp_node = Void or else Result = False 401 loop 402 if (tmp_node.left = Void or else tmp_node.left.index < tmp_node.index) and then (tmp_node.right = Void or else tmp_node.right.index > tmp_node.index) then 403 if tmp_node.parent = Void then 404 if tmp_node /= root then 405 Result := False 406 else 407 if tmp_node.right = Void then 408 tmp_node := Void 409 else 410 tmp_node := lowest_node_in_subtree(tmp_node.right) 411 splay(tmp_node) 412 end 413 end 414 elseif tmp_node.parent.left = tmp_node then 415 if tmp_node.right = Void then 416 tmp_node := tmp_node.parent 417 else 418 tmp_node := lowest_node_in_subtree(tmp_node.right) 419 splay(tmp_node) 420 end 421 elseif tmp_node.parent.right = tmp_node then 422 if tmp_node.right /= Void then 423 tmp_node := lowest_node_in_subtree(tmp_node.right) 424 splay(tmp_node) 425 else 426 tmp_node := Void 427 end 428 else 429 Result := False 430 end 431 else 432 Result := False 433 end 434 end 435 end 436 end 437 438feature {INDEXED_LIST} 439 splay (node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I]) 440 require 441 node_not_void: node /= Void 442 local 443 parent: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 444 do 445 from 446 until 447 node = root 448 loop 449 if node.parent = root then 450 -- In this case we only need to zig. 451 parent := node.parent 452 if node = parent.left then 453 rotate_right(node) 454 else 455 rotate_left(node) 456 end 457 root := node -- Make sure root is update! 458 elseif node = node.parent.left then 459 if node.parent = node.parent.parent.right then 460 rotate_right(node) 461 rotate_left(node) 462 else 463 rotate_right(node.parent) 464 rotate_right(node) 465 end 466 if node.parent = Void then 467 -- Make sure to update the root if 468 -- necessary. 469 root := node 470 end 471 elseif node = node.parent.right then 472 if node.parent = node.parent.parent.left then 473 rotate_left(node) 474 rotate_right(node) 475 elseif node.parent = node.parent.parent.right then 476 rotate_left(node.parent) 477 rotate_left(node) 478 end 479 if node.parent = Void then 480 -- Make sure to update the root if 481 -- necessary. 482 root := node 483 end 484 end 485 end 486 end 487 488 rotate_right (node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I]) 489 require 490 node_not_null: node /= Void 491 local 492 parent: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 493 do 494 parent := node.parent 495 parent.set_left(node.right) 496 if node.right /= Void then 497 node.right.set_parent(parent) 498 end 499 if parent.parent = Void then 500 node.set_parent(Void) 501 else 502 node.set_parent(parent.parent) 503 if parent = parent.parent.left then 504 parent.parent.set_left(node) 505 else 506 parent.parent.set_right(node) 507 end 508 end 509 node.set_right(parent) 510 parent.set_parent(node) 511 end 512 513 rotate_left (node: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I]) 514 require 515 node_not_null: node /= Void 516 local 517 parent: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] 518 do 519 parent := node.parent 520 parent.set_right(node.left) 521 if node.left /= Void then 522 node.left.set_parent(parent) 523 end 524 if parent.parent = Void then 525 node.set_parent(Void) 526 else 527 node.set_parent(parent.parent) 528 if parent = parent.parent.left then 529 parent.parent.set_left(node) 530 else 531 parent.parent.set_right(node) 532 end 533 end 534 node.set_left(parent) 535 parent.set_parent(node) 536 end 537 538feature {AUX_PH01_SPLAY_DICTIONARY} 539 root: AUX_PH01_SPLAY_DICTIONARY_ITEM[E, I] -- references the root of the tree. 540 541invariant 542 root_null_no_count_integrity: root = Void implies count = 0 and root /= Void implies count /= 0 543 count_valid: count >= 0 544 -- The following invariant is very heavy-duty. I've already tried it 545 -- and it seems to be ok so I'm commentint it out now. If I make any 546 -- more serious changes to this class I'll uncomment this invariant 547 -- and use it until I'm happy. 548 -- dictionary_has_integrity : has_tree_integrity 549 550end -- class AUX_PH01_SPLAY_DICTIONARY 551-- 552-- ------------------------------------------------------------------------------------------------------------------------------ 553-- Copyright notice below. Please read. 554-- 555-- SmartEiffel is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, 556-- as published by the Free Software Foundation; either version 2, or (at your option) any later version. 557-- SmartEiffel is distributed in the hope that it will be useful but WITHOUT ANY WARRANTY; without even the implied warranty 558-- of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have 559-- received a copy of the GNU General Public License along with SmartEiffel; see the file COPYING. If not, write to the Free 560-- Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 561-- 562-- Copyright(C) 1994-2002: INRIA - LORIA (INRIA Lorraine) - ESIAL U.H.P. - University of Nancy 1 - FRANCE 563-- Copyright(C) 2003-2006: INRIA - LORIA (INRIA Lorraine) - I.U.T. Charlemagne - University of Nancy 2 - FRANCE 564-- 565-- Authors: Dominique COLNET, Philippe RIBET, Cyril ADRIAN, Vincent CROIZIER, Frederic MERIZEN 566-- 567-- http://SmartEiffel.loria.fr - SmartEiffel@loria.fr 568-- ------------------------------------------------------------------------------------------------------------------------------