Compare commits

..

7 Commits

66 changed files with 23 additions and 3636 deletions

View File

@ -5,7 +5,7 @@
<excludeFolder url="file://$MODULE_DIR$/.venv" />
<excludeFolder url="file://$MODULE_DIR$/venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.12 (AlgoDatSoSe25)" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Python 3.12 (SoSe25)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -1,141 +0,0 @@
#############################################################################################################################################
#...#.#.........#...#.....#.........#.....#.......#.................#...#.....#.......#.....#.......#.......#...............#.....#........E#
#.#.#.#.#.#.#####.#.#.###.#.#.#####.#.#.#.#.#####.###.#.###########.#.#.#.###.#.#.#####.#.###.###.#.#.#######.#######.#####.#.###.#.#######.#
#.#...#...#.#.....#.#.#.........................#...#.#.....#...#.....#.#...#.#.#.......#.....#...#...#.....#.#...#...#.#...#...#.#.....#.#.#
#.#####.#.#.#.#####.#.#.#.#.###.###.#.#.#.###.#.###.#######.#.#.#########.###.#.###############.#######.###.#.#.#.#.###.#.#####.#.#####.#.#.#
#.......#.#...#...#.#.#.#...#.................#.#.........................#...#.#...#.........#...#.....#...#.#.#.#.....#.#.....#...#.....#.#
#.#.#####.#####.###.#.#.#####.###.#.###.###.###.#########.#.#.###.#.#######.###.#.###.#######.#.#.#.#####.###.###.###.#.#.#.#.#####.###.###.#
#.#.......#.......#.#...#.......#.#...#.....#...#...#.........#.#...#.....#.#...#...#...#.....#.#...#.....#...#.....#.#...#.#.#...#...#.#...#
#.###.###.#######.#.###.#.#####.#.###.###.###.###.#.#######.#.#.#######.#.#.#.#####.###.###.#########.#####.###.#####.#.#####.#.#####.###.#.#
#...#.#.#...#.....#...#.#.#...#.#.............#...#.....#...#...#.......#...#.....#...#...#...........#.....#.#...#...#.#...#.#.....#.....#.#
###.#.#.#.#.#.###.###.#.#.#.#.#.###.###.#.#.#.#.#.#####.#######.#.###.###.#.#####.#.#.###.###########.#.#####.#.#.#.###.#.#.#.#.###.#######.#
#.....#.................#...#.#...#.#.#...#.#.#.#.....#.......#.#...#.#.#.#.......#.#...#.....#.......#.#.#.....#.#.#.....#...#.#.......#.#.#
#######.#.#.#.#.#.#.#########.#####.#.###.#.#.#.#.#.#########.#.###.#.#.#.#########.#######.#.###.#####.#.#.#####.#.###########.#.#####.#.#.#
#.....#.#.#.#.#.#...#.........#...#.#.#...#.#...#.#.......#...#.....#.#.............#.....#.#...#.#.....#.....#...#.......#...#.#...#.....#.#
#.###.#.###.###.###.#.#.#######.#.#.#.#.#.#.#####.#####.#.#.#######.#.#########.#####.###.#.###.###.###########.#.#######.#.#.#####.#######.#
#.#...#...#.....#.#.#.#.#.....#.#...#.#...#...#.......#.#.#.......#.#...#.....#.#.........#...#...#...#.........#...#.#...#.#.....#.........#
#.###.###.#######.#.###.#.###.#.#####.###.###.#.#######.#.#####.###.#.#.#####.#.#.#######.#######.###.###.#########.#.#.###.#####.#.#########
#...#...#.............#.#.#.#...#.#.......#.#.#.#.......#.#...#.....#.#.#.....#.........#...#.....#.#.....#.#.....#.#.#...........#.#.......#
#.#.###.#############.#.#.#.#####.#.#######.#.#.#.#######.###.#####.###.#.###.#.#######.###.#.###.#.#######.#.###.#.#.#######.#.#.#.#####.#.#
#.#.#...............#...#.#.....#...#...#.....#.#.#.....#.....#...#.....#...#.#...#.....#.#.#...#...#.......#.#.#...#.......#.#.#.#.....#.#.#
#.#.###############.###.#.#.###.#.###.#.#.#####.#.###.#######.#.#.#.#.#####.#.###.#.#####.#.###.#####.#.#####.#.#########.###.#.#.#####.#.#.#
#.#.......#.......#.#...#.#...#.#.#...#...#.#...#.#...#.....#.#.#...#.....#.#.#...#.#.....#...#.....#.#.#...#.....#.......#...#...#...#...#.#
#########.#####.#.#.#.###.###.#.#.#.#######.#.###.#.###.###.#.#######.###.#.#.#.###.#.#######.###.#.#.#.#.#.#####.#.#######.#########.#####.#
#...#...#...#...#.#.#.#...#...#.#.#.#.............#.....#...#...#...#...#.#.....#...#...#...#.#.......#.#.#.....#.#.......#.#...#.....#.#...#
#.#.#.#.###.#.###.#.###.###.#.###.#.#############.#.#####.###.#.#.#.#####.#.#####.#####.#.#.#.#.#.###.#.#.###.#.#.#######.#.###.#.#.#.#.#.###
#.#...............#.....#...#.#...#.....#.....#...#.#.#...#.....#.#.......#.....#.....#...#.#...#...#.#...................#...#...#.#...#...#
#.#######.#.#.###########.#.###.#######.#.###.#.###.#.#.###.#####.###########.#####.#.###.#.#######.#################.#####.#.#####.###.###.#
#.....#.....#.#...............#...#...#.#.#.#...#.....#...#...#.......#...#...#...#.#...#.#.......#...#.........#...#.#...#.#.....#.#...#...#
#####.#######.#.#############.###.#.###.#.#.#############.###.###.###.#.###.###.#.###.#.###.#########.#.#######.#.#.#.#.#.#######.#.#####.###
#.....#.....#.#.............#.....#...#...#.........#.......#...#...#.#.......#.#...#...............#.#...#.#...#.#...#.#.....#...#.#...#...#
#.#####.###.#.#############.#########.#####.###.###.#.#####.###.#####.#.#.#####.###.#.###.#########.#.###.#.#.###.#####.#####.#.###.#.#.###.#
#.#.......#.#...#.......#...#.......#.....#...#.#.....#.#.....#.......#...#...#.#...#...#.#.......#.#.#...#...#.......#.#.#...#.#...#.#.....#
#.#.#######.#.#.#.###.###.###.#####.###.#####.#.#######.#.###########.#####.#.#.#.#####.#.#.#####.#.#.#.###.###########.#.#.###.#.#.#.#######
#.#.#.....#.#.#.#...#.....#.#.....#...#.......#...#.......#.....#...#.#.....#...#.....#.#.#...#.....#.#.#.#...........#.#.#.#...#.#.........#
#.#.#.###.#.#.#####.#######.#.#.#.###.###########.#######.#.###.#.#.#.#.#############.###.#.#.#####.#.#.#.#########.#.#.#.#.#.#####.###.###.#
#...#...#.#.#.....#.......#...#...#.#...#.......#...#...#.#...#...#...#.#.....#.....#...#.#.#.....#.#...#.........#.#.#.#...#.....#.....#...#
#.#####.#.#.#.#.#########.#####.###.###.#.#####.#.#.#.#.#####.#########.###.#.#####.###.#.###.###.#.#.#.#.#.#####.#.#.#.#.###.###.#.###.#####
#...#.#.#...#.#.........#.....#.#...#...#.....#...#...#.........#...#.#...#.#.....#...#.#...#.#...#.#.#.#.#.#...#.#.#...#.#.#.#...#...#.....#
###.#.#.#####.#######.#.#####.#.#.#.#.#######.###.#.###########.#.#.#.###.#.#####.#.###.###.#.#.###.#.#.#.###.#.#.#.#####.#.#.#.#.###.#.###.#
#.#.#.#...#.#.#...#...#.....#.#.#.#...#...#.....#.#.#.........#...#...#...#...#.....#...#...#.#.#...#...#.....#.#.#.#.....#.................#
#.#.#.###.#.#.###.#.#########.#.#.#####.#.#.###.#.#.#.#######.#######.#.#####.#.#####.###.#####.###############.#.#.#.#####.#.#.###.###.#.#.#
#.#.#...#.#.....#.#.............#...#...#.#...#.#.#.#.#.....#.......#.#...#...#.#...#.....#...#.......#.....#...#...#.#.......#...#.#...#.#.#
#.#.#.###.#####.#.#########.###.###.#.###.###.#.#.#.#.#.#.###.#.#.###.###.#.#####.#.###.#.#.#.#####.#.#.###.#.#######.#.#########.###.#.#.#.#
#...#.........#...#...#...#.....#.#.#.#.#.....#...#.#.#.#.....#.#.....#...#.#...#.#...#.#.#.#...#...#.#.#.....#.....#.#.............#.#.#.#.#
#.#####.#####.###.###.#.#.#.###.#.#.#.#.#######.#####.#.###.#.#.#######.###.#.#.#.###.#.#.#.###.#.###.#.#######.###.#.###.#.#######.#.#.#.###
#.#.........#...#.#...#.....#.........#.......#.......#...#...#.........#...#.#...#...#...#...#...#.....#.........#.#.....#.#.......#...#...#
#.###.#####.###.#.#.#.#.#######.#.#########.#############.###.###########.#.#.#####.#######.#.#########.#.#########.#####.###.###.#####.###.#
#...#...#...#.#.#...#.#.#.....#...#.......#...#.......#...#...#.......#...#...#...#.....#...#...#.....#.#.#...#.........#...#...#.#.........#
###.#.#.#.###.#.#####.#.#.###.#####.###.#.###.#.###.#.#####.#.###.###.#.#.###.#.#.#####.#.#####.#.#.#.###.###.#.#.#######.#.###.###.#.#.#.#.#
#...#.#.#.#...#.......#...#...#.....#.#.#...#...#.........#.#.....#.#.#.#.#...#.#.....#.#...#...#.#.#.....#...#.#.#.......#...#...#.#.....#.#
#.#####.#.#.#.#######.#####.###.#####.#.###.#####.#######.#.#######.#.#.###.###.#.###.#.###.#.#.#.#.#######.###.#.#.###.#####.#.#.#.###.###.#
#.#.....#...........#.....#.....#...#.#...#.....#.#...#...#...#.#...#...#...#.......#.#...#.#.#.#.#.......#.#...#.#...#...#...#.#...#.....#.#
#.#.#.#####.#.#####.#####.#.#####.#.#.###.#####.#.#.#.#.#####.#.#.#.###.#.###.###.#.#.###.#.#.#.#.###.###.#.#.#######.#.#.#.#.#.#.###.###.#.#
#.............#...#.....#.#.......#...#.#.....#...#.....#.....#.#.#.....#.#...#.....#...#...#.#.#.....#.#.#.#.......#.#...#.#.......#...#...#
#.#.###.###.###.#.#####.#.###########.#.#.###.#####.#######.###.#.#######.#####.#######.#####.#.#######.#.#.#####.###.#.#.#.#####.###.#.###.#
#.#.#...#.......#.#...#.#.#.....#...#.#.....#...#...#.......#.#.........#.......#.....#...#...#.......#...#.....#.....#.#.#.........#.#...#.#
#.#.#.#.#.#.#####.#.#.###.#.###.#.#.#.#.#.#####.#.#####.#.###.#.#####################.###.#.#########.#.###.###.#######.#.#######.#.###.#.###
#.....#.........#.#.#.#.....#.#.#.#.#.#.#.#.....#.#...#.#.....#...#...#.........#...#.#...#.....#.....#.....#.#.#.......#...#.....#...#.#...#
#.###.#.###.###.#.#.#.#.#.#.#.#.#.###.#.###.#####.#.#.#.#.#.###.###.#.#.#.#.###.#.#.#.#.#######.#####.#######.#.#.###.###.#.#.#.#.###.###.#.#
#.....#.#.....#.#...#...#.#...#.#...#.#...#...#.....#...#.#.#...#...#...#.........#...#.#.#.....#...#.#.......#...#.......#...#.#...#...#.#.#
#######.###.###.#########.###.#.#.#.#.###.###.#########.#.#.#.###.#.###.###.#########.#.#.#.###.#.#.#.###.#.#####.#.#####.#######.#.###.###.#
#.#...#...#.#...#.....#...#...#.#.#.........#.#.........#.#.#...#.#...#...#.#.......#.#.#.#.#...#.#.#.....#.#.....#.#.....#...#...#...#.....#
#.#.#.###.#.#.#######.#.###.###.#.#########.#.#.###.###.#.###.#.#.#.#.#.###.#.#####.###.#.#.#.###.#.###.#####.#####.#######.#.#.#####.#####.#
#...#...#...#.......#.#...#.#...#.#.......#.#...#.......#.......#.#.#.#.#...#...#.#...#.#.#.#.#...#.......#...#...#.....#...#...............#
#.###.#.###.#######.#.###.#.#.#####.#####.#######.#.#############.#.#.#.#.#.###.#.###.#.#.#.###.#########.#.###.#.#####.#.#######.#.###.#.###
#.#.#...#...#.....#.#.....#.#.#.....#...#.........#.........#.....#.#.#.#.#.#...#...#...#.#.....#.#.........#...#...#.......................#
#.#.###.#.#######.#.#######.#.#.#####.#.#.#.#######.###.###.#.#####.#.###.#.#.###.#.#####.###.###.#.#.#########.#####.#.###.#.#.###.###.#.#.#
#.....#.#.........#...#.....#.#.....#.#.#.#.....#...#.....#...#.....#...#.#.#...#.#.............#...#...........#.......#...#.#.#...........#
#####.#.#######.#####.#.#####.#####.#.#.#.#####.#.###.###.#####.#######.#.#####.#####.#####.###.#.###########.###.#####.#.#####.#####.#.#.#.#
#.#...#.....#...#.....#.#...#.#.....#...#.....#.....#.#...#.#...#...#...#.#...#.....#.........#.#...#.......#...#.#.....#...#...#.....#.#.#.#
#.#.#######.#.###.#.###.#.###.#.#####.#.#####.#####.###.#.#.#.#####.#.###.#.#.#####.#######.#.#####.#.#####.###.#.###.#####.#.#.#.#######.#.#
#.#.#.....#...#...#.#...#...#.#...#...#...#.#.....#.....#...#.......#...#...#.....#.#.....#.#.....#.#.#.....#.#.#...#.#...#...#.#.......#.#.#
#.#.#.###.#####.###.#.#####.#.#.#.#.#.###.#.#.###.#########.#.#####.#####.#####.#.#.#.###.#####.###.#.#.#####.#.###.#.###.#####.#######.#.#.#
#.#.#.#.......#...#.#.#.....#.....#.#...#.#.....#.........#.#.......#...#...#...#.#.......#...#.#.....#.......#.#...#.....#...#.......#.#.#.#
#.#.#.#######.#.#.#.#.#.###.#.#####.###.#.#.###.#########.###.#######.#.#.###.#########.###.#.#.#.#.#######.###.#.#####.###.#.#.#######.#.#.#
#...#.....#.#.#.#.#.#.#.#...#.........#.#...#...#.....#.#...#.....#...#...#...#.....#.......#.#.#.#...........#.#.#...#...#.#...#.......#.#.#
#.#######.#.#.###.#.#.#.#.###.#########.#####.#####.#.#.###.#####.#.#######.#.#.#.#.#.###.###.#.#.#.#########.#.#.#.#.#.#.#.#####.#######.#.#
#.#.......#.......#.#...#.#.#.#.........#...#.......#.#...#.#.....#...#.#...#.#.#.#.#.....#.#.#...#.......#.#.#.#...#...#.#.#...#.....#...#.#
#.#.#######.#####.#######.#.#.#.#########.###########.#.###.#.#######.#.#.###.#.#.#########.#.#######.#.#.#.#.#.#########.#.#.#.#####.#.#.#.#
#.#.#.......#...#.#.......#...#.....................#...#...#.#...#...#.#...#.#.#.#...#...#...#...#...#.#.....#...#...#...#...#.....#...#...#
#.#.#########.#.###.###########.#.###.#########.#.#####.#.###.#.###.###.###.###.#.#.#.#.#.#.###.#.#.#.#.#.#.###.#.#.#.#.###########.#####.#.#
#.#.#.............#...#.#.......#...#.....#...#.#.....#.#.....#.......#...#.....#...#...#.#.#...#.#.#.#.#.#.....#.#.#.#.#.........#.....#.#.#
#.#.#.#####.#.###.###.#.#.#.#########.###.#.#.#######.#.#############.###.###############.#.#.###.#.#.#.#.#####.#.#.#.#.#.#####.###.###.#.#.#
#.#.#.#.#...#.#.#.....#...#.............#...#.......#.#.#...........#.....#.......#.....#.#.#.#.#...#.#.#.#.......#.#.#.#...#.#.........#.#.#
#.#.#.#.#.#.#.#.#########.#.#####.###.#########.###.#.#.#.#########.#####.#.#####.###.#.#.#.#.#.#.###.###.#########.#.#.###.#.#####.#######.#
#.#.....#.#.#.#.........#...#.......#.#.......#.#...#...#...#...#...#...#...#.........#.#.....#.......#...#.......#.#...#...#.....#.........#
#.###.###.#.#.#.#######.#####.###.#.###.###.#.#.#.#####.#.#.#.#.###.#.#.###############.#######.###.###.#.#.#####.#.###.#.#####.#.#.#######.#
#...#.....#.#.#.#.#...........#...#.....#.....#.#.....#...#.......#...#.............#.....#...#.#.......#.#.#.......#...#.....#.............#
###.#.#####.#.#.#.#.#.###########.#######.###########.#.#.#######.#.#.#############.#######.#.#.#.#.#####.#.###.###.#.#######.#.###.#.###.#.#
#...#.#...#.#...#.#.#...#.......#.......#...#.....#...#.#...#.....#...#...........#.........#.....#.#...#.#...#...#.#.......#...#.....#...#.#
#####.#.#.#.#####.#.#.#.###.###.#####.#.###.#.###.#.###.#####.#########.#####.###############.#.#####.#.###.#.###.#.#.###.#########.#######.#
#...#...#.#.#...#...#.#...#...#.....#.#.#.#...#.#.#.#.#.....#.#...#...#.....#.#.............#.#.#.....#...#.#...#...#...#.........#...#.....#
#.#.#.###.#.#.###.###.###.###.#####.#.#.#.#####.#.#.#.#####.#.#.#.#.#.#.###.###.###.#.#######.###.#######.#.###.#####.#####.#.###.#.#.#.#####
#.#.......#...#...#...#.#.....#...#...#.....#...#...#.#.....#...#.#.#.............#.#.#.......#...#.....#.#...#.......#...#.#.#...#...#.....#
#.###########.#.###.###.#########.#########.#.#.###.#.#.#########.#.###########.###.#.#.#######.#######.#.#############.#.###.#.###.#######.#
#...#...#...#.#.#...#.#...........#.......#.#.#...#...#.#.........#...#.......#.#...#.#.#...........#...#...#...........#...#.#...#.......#.#
###.#.#.#.#.###.#.###.#.###.###.###.###.###.###.###.#.#.#.#########.###.#####.###.#.###.#.#########.#.###.#.#.#############.#.###.#.#.###.#.#
#.#...#...#...#.#.#.......#.#...#.....#.......#...#...#.#...#.....#.#...#...#.#.........#.#...#.....#.....#.#...#.............#.#.#.#...#.#.#
#.###########.#.#.#########.#.###.#######.###.#.#.#.#.#.#.#.###.###.#.###.#.#.#.#.#.#####.###.#.#.#####.#.#.#.#.#.#############.#.#.###.#.#.#
#.#.........#...#.#.......#.#.#...#.......#.#...#.#.#.....#...#.#...#.....#.#...#.#...#.#...#.#.......#.#...#.#.#.....#.......#.#.........#.#
#.#.#######.#####.#.#####.#.###.###.#####.#.#.###.#.#####.###.#.#.#########.#####.###.#.#.#.#.#######.#.#######.#####.#.#####.#.###.###.###.#
#...#.#...........#.#.....#.....#...#...#.#.#.#...#.#...#...#.#...#.......#.....#.#.#.#.....#.#.......#...#...#.#.....#.....#.#...#.#.....#.#
#.###.#.#######.#.#.#.###.#.#####.###.#.#.#.#.#.###.#.#.#####.#.#####.#.#######.#.#.#.#.#####.#.#########.#.#.#.#########.###.#.###.#.#.#.#.#
#.....#.......#.#...#.#...#...#.#.#...#.#.#...#...#.#.#.......#.#...#.#.....#...#...#.#.#.....#.#.......#.#.#...#.........#...#...#.#...#.#.#
###.#########.#.#####.#.#####.#.#.#.###.#.#.###.#.#.#.#########.#.#.###.#.#.#.#.#####.#.#.#####.#.#.#####.#.#####.#########.#####.#.###.#.#.#
#...#.........#...#...#.#.......#.#.....#.#.....#.#.#.#...#.......#...#...#.#.#.....#.#.#.....#.#.#.#...........#.......#.#.#...#...#...#...#
#.###.###########.###.#.#########.###.###.#####.#.#.#.#.#.#.#########.#.###.#.#####.#.#.#####.#.#.###.#######.#.#######.#.#.#.#.#.#.#.#.#####
#...#.#.......#.#.....#...#.....#...#...#.....#...#...#.#...#.........#.#...#.....#...#.......#.#.#...#.....#.#.#.....#.#.#...#.#...#...#...#
###.#.#.###.#.#.#####.###.#.###.###.###.#####.#########.###.#.#########.#.#####.#.#####.#######.#.#.###.###.#.#.#.#.###.#.#####.###.###.###.#
#.#.#.#...#.#...#...#.#...#.#.#.....#.......#.............#.#.....#...#.#.#...................#.#.#.#...#...#.#.....#...#.......#.....#...#.#
#.#.#.#####.#####.#.#.#.###.#.#######.###################.#######.#.#.#.#.#.#.###.###########.#.#.#.#.#####.###.#.#.#.###.###.#.#.#.#.#.#.#.#
#...#.....#.......#.........#...#.....#.........#.......#.........#.#...#.#.#...#.#...#.#.....#.#...#.....#.....#.#.#.#.....#.#...#...#...#.#
#.#######.#####.#############.#.#.###.#.#####.#.#.###.#############.#####.#####.#.#.#.#.#.#####.#.###.###.#####.###.#.#.###.#.#####.###.###.#
#...#...#.....#.....#...#.....#...#...#...#...#.......#...........#...#.#.#...#.#.#.#.#.........#...#...#.....#.#...#.#...#.#.....#...#.#...#
###.#.#.#####.#####.#.#.#.#.#######.#####.#.###########.#####.###.#.#.#.#.#.#.#.#.#.#.#######.#####.#########.#.#.###.#.#.#.#########.#.#.#.#
#.#.#.#...#...#.....#.#...#...#...#.......#...#...#.......#...#.#.#.#.#.....#.#.#.#.#.....................#...#...#...#.#.#.....#...#...#.#.#
#.#.#.###.#.#########.#######.#.#.###########.#.#.#.#######.###.#.###.#.#####.#.#.#.#.#.#.###.###.#.#####.#.#####.#.###.#.#####.#.#.###.#.###
#.#.#...#.#...#.......#.......#.#...........#...#.#.#.#.....#...#...#.#.#.....#.#.#.#.....#...#.....#...#...#.#...#.#.#.......#...#...#.....#
#.#.###.#####.#.#.#########.###.###.#######.#####.#.#.#.#####.#.###.#.#.#.#####.#.#.###.###.###.###.#.#.#####.#.###.#.#.#####.#####.#.#.###.#
#...#...#.....#.#.........#.......#.....#.#.#...#.....#...#.#.#...#...#...#.....#.#...#.....#...#...#.#.......#...#.#...#...#.#.....#.#.#...#
#.###.#.#.#.###.###.###.#.#######.#####.#.#.#.#.#.###.###.#.#.###.#####.###.#.#######.#.#####.###.###.#######.###.#.#.###.#.#.#.#####.#.#.#.#
#.#...#.#...#...#...#...#.......#.....#.#...#.#.#...#.#...#.#...#...........#.#...#...#.....#...#...#.#...#...#...#.#...#.#.#.#...#.#.#...#.#
#.#.###.###.#.###.#.#.#########.###.###.#.#####.#.#.#.#.###.###.#########.#####.#.#.#######.#.#####.#.#.#.#.#.#.###.#####.#.#####.#.#.#.###.#
#...#.#.#...#.#...#...#.......#.#...#...#.#.....#.#.#.#...#.#.............#.....#.#.#...#.#...#.....#.#.#.#.#.#.#.#.....#.#.......#.....#...#
#####.#.#.#.#.#.#######.#####.#.#.###.###.###.#.#.#.#.###.#.#.###.#.###.#.#.#####.#.#.#.#.#####.#####.#.###.#.#.#.#####.#.###############.###
#.....#.#.#.#.#.#.....#.....#...#...#.#.#.....#.#.#.#...#.#...#...#...#.#.#.#.#...#.#.#.#.....#.#.#...#...#.#.#...#...#.#.............#...#.#
#.#.#.#.#.#.#.#.#.###.#######.###.###.#.#.#####.#.#.#.###.#####.###.#.#.#.#.#.#.###.#.#.#####.#.#.#.#####.#.#.###.#.#.#.#.#.#########.#.###.#
#.#.#.#.#...#.#.....#...#...#.........#...#.....#.#.......#...#...#.#.#...#.#.#.......#...................#.#.#...#.#.#.#...#.......#.#...#.#
#.#.###.###.#.#####.###.#.#.###########.###.#####.#.#.#####.#.###.#.#.###.#.#.###########.###.#.#.#####.#.#.#.#.#####.#.###.#####.#.#.###.#.#
#.#.....#...#.#...#...#.#.#.......................................#.........#.....#.......#...#...#.....#.#.#.#.#...#.#.#.........#.#...#...#
#.#######.#.#.#.#.#####.#.#########.#.#.#####.#.#.#.#.#############.#.###.#.#.#####.#####.###.#.#.#.#####.#.###.#.#.#.#.###.#######.###.###.#
#.#...............................#.#...#.....#.#.#.#...#...............#.....#.....#.........#.#.......#.#.......#...#.#...#...#...#.#...#.#
#.#.#######.###.#####.#.###.#.#.###.#.#####.###.#.###.#.###########.#.#.#.#####.###.#####.###.#.#######.#.#####.#####.#.#.#.#.###.###.###.###
#...#.....#.#...#.....#...#.#.#.#...#.#...#.........................................#...#...#...#.....#.......#...#...#...#.#...#.......#...#
#.#.#.###.#.#.###.#######.#.#.#.#.###.#.#.###.#.#####.#######.#.#.#.#.#####.#.#######.#.#.#####.#.###.#####.###.#.#########.###.#.#########.#
#.#.#.#.#...#.#.....#.......#...#...#.#.#.....#.....#.....#...#.#.#.#.#.....#.........#.#.....#.#.#.#...#...#.....................#.....#...#
#.###.#.#####.#####.#.#####.#######.#.#.###########.#.###.#.###.#.###.###.#.###########.#.###.#.#.#.###.#####.###.#.###.#####.#.###.###.#.#.#
#...#.#.....#...#...#.#...#.#.......#.#.#.......#...#...#...............#.#.........#.#.#.............#.....#.#.#...#.#.....................#
#.#.#.###.#.###.#.#####.#.###.#######.#.#.#.#####.###.#.#.#########.###.#.#.#.#.###.#.#.#.#######.#.#.#####.#.#.#####.#####.#.###.###.###.#.#
#S#.......#.....#.......#.....#.........#...............#...............#.....#.......#.............#.....#...............#.................#
#############################################################################################################################################

View File

@ -1,15 +0,0 @@
###############
#.......#....E#
#.#.###.#.###.#
#.....#.#...#.#
#.###.#####.#.#
#.#.#.......#.#
#.#.#####.###.#
#...........#.#
###.#.#####.#.#
#...#.....#.#.#
#.#.#.###.#.#.#
#.....#...#.#.#
#.###.#.#.#.#.#
#S..#.....#...#
###############

View File

@ -1,5 +0,0 @@
Sabqponm
abcryxxl
accszExk
acctuvwj
abdefghi

View File

@ -1,15 +0,0 @@
###############
#.......#....E#
#.#.###.#.###.#
#.....#.#...#.#
#.###.#####.#.#
#.#.#.......#.#
#.#.#####.###.#
#...........#.#
###.#.#####.#.#
#...#.....#.#.#
#.#.#.###.#.#.#
#.....#...#.#.#
#.###.#.#.#.#.#
#S..#.....#...#
###############

View File

@ -1,8 +0,0 @@
"Höhleneingang";"Ost/West-Passage";5
"Höhleneingang";"Nord/Süd-Passage";3
"Nord/Süd-Passage";"Nebelraum";7
"Steiniger Pfad";"Ost/West-Passage";2
"Ost/West-Passage";"Schwefelgewölbe";4
"Schwefelgewölbe";"Steiniger Pfad";1
"Schatzkammer";"Nebelraum";2
"Steiniger Pfad";"Schatzkammer";6

View File

@ -1,8 +0,0 @@
"Höhleneingang" <> "Ost/West-Passage"
"Höhleneingang" <> "Nord/Süd-Passage"
"Nord/Süd-Passage" <> "Nebelraum"
"Steiniger Pfad" > "Ost/West-Passage"
"Ost/West-Passage" <> "Schwefelgewölbe"
"Schwefelgewölbe" > "Steiniger Pfad"
"Schatzkammer" > "Nebelraum"
"Steiniger Pfad" > "Schatzkammer"

View File

@ -1,25 +0,0 @@
"Höhleneingang" <> "Ost/West-Passage"
"Höhleneingang" <> "Nord/Süd-Passage"
"Nord/Süd-Passage" <> "Nebelraum"
"Steiniger Pfad" > "Ost/West-Passage"
"Ost/West-Passage" <> "Schwefelgewölbe"
"Schwefelgewölbe" > "Steiniger Pfad"
"Schatzkammer" > "Nebelraum"
"Steiniger Pfad" <> "Schatzkammer"
"Steiniger Pfad" > "Höhleneingang"
"Kristallhöhle" <> "Schwefelgewölbe"
"Kristallhöhle" <> "Nebelraum"
"Versteckter Gang" > "Kristallhöhle"
"Versteckter Gang" > "Schatzkammer"
"Unterirdischer See" <> "Kristallhöhle"
"Unterirdischer See" <> "Ost/West-Passage"
"Geheimgang" > "Unterirdischer See"
"Geheimgang" > "Versteckter Gang"
"Abgrund" > "Geheimgang"
"Abgrund" > "Nebelraum"
"Verlorene Kammer" > "Abgrund"
"Verlorene Kammer" > "Schwefelgewölbe"
"Geheimgang" > "Schatzkammer"
"Kristallhöhle" > "Höhleneingang"
"Schwefelgewölbe" > "Höhleneingang"
"Abgrund" > "Schatzkammer"

View File

@ -1,9 +0,0 @@
xxxxxxxxxxxxxxxxxxxxx
x x
x S x
x x
x xxxxxxxx x
x x
x x
x A x
xxxxxxxxxxxxxxxxxxxxx

View File

@ -1,5 +0,0 @@
xxxxxAxxxxxxxxx
x xSx
xxxxxxxxxx xx x
x x
xxxxxxxxxxxxxxx

View File

@ -1,150 +0,0 @@
from utils.memory_array import MemoryArray
from utils.memory_cell import MemoryCell
from utils.memory_manager import MemoryManager
from utils.literal import Literal
import random
class PriorityQueue:
def __init__(self, size: Literal):
self.items = MemoryArray(size)
self.heapsize = MemoryCell(0)
def __len__(self):
return self.heapsize.value
def insert(self, item: MemoryCell):
if self.heapsize == self.items.length():
raise Exception("Queue is full")
self.heapsize.set(self.heapsize.succ())
self.items[adjust_index(self.heapsize)].set(item.value)
heapyfy_up(self.items, self.heapsize)
def pop(self) -> MemoryCell | None:
if self.is_empty():
return None
result = MemoryCell(self.items[Literal(0)])
self.heapsize.set(self.heapsize.pred())
if self.heapsize > Literal(1):
swap(self.items, 0, int(self.heapsize))
max_heapyfy(self.items, Literal(1), self.heapsize)
return result
def peek(self) -> MemoryCell | None:
if self.is_empty():
return None
return MemoryCell(self.items[Literal(0)])
def is_empty(self) -> bool:
return self.heapsize == Literal(0)
def __str__(self):
result = "[ "
for i, cell in enumerate(self.items.cells):
if i == int(self.heapsize):
result += "| "
result += str(cell) + " "
result += "]"
return result
def left_child(i: Literal):
return Literal(2 * int(i))
def right_child(i: Literal):
return Literal(2 * int(i) + 1)
def adjust_index(i: Literal):
return i.pred()
def heapyfy_up(z: MemoryArray, i: Literal):
if i == Literal(1):
return
parent = Literal(int(i) // 2)
if z[adjust_index(parent)] >= z[adjust_index(i)]:
return
swap(z, int(i)-1, int(parent)-1)
heapyfy_up(z, parent)
def max_heapyfy(z: MemoryArray, i: Literal, heapsize: Literal):
l = left_child(i)
r = right_child(i)
with MemoryCell(i) as max_value:
if l <= heapsize and z[adjust_index(l)] > z[adjust_index(i)]:
max_value.set(l)
if r <= heapsize and z[adjust_index(r)] > z[adjust_index(max_value)]:
max_value.set(r)
if max_value != i:
swap(z, int(i)-1, int(max_value)-1)
max_heapyfy(z, max_value, heapsize)
def swap(z: MemoryArray, i: int, j: int):
tmp = z[Literal(i)].value
z[Literal(i)] = z[Literal(j)]
z[Literal(j)].set(tmp)
def analyze_complexity_insert(sizes, presorted=False):
"""
Analysiert die Komplexität der Insert-Funktion.
"""
for size in sizes:
MemoryManager().purge() # Speicher zurücksetzen
pq = PriorityQueue(Literal(size))
insert_list = [random.randint(-100, 100) for _ in range(size)]
if presorted:
insert_list.sort()
for insert_value in insert_list[:-1]:
pq.insert(MemoryCell(insert_value))
MemoryManager().reset()
pq.insert(MemoryCell(insert_list[-1]))
MemoryManager.save_stats(size)
MemoryManager.plot_stats(["cells", "compares", "writes"])
def analyze_complexity_pop(sizes, presorted=False):
"""
Analysiert die Komplexität der Pop-Funktion.
"""
for size in sizes:
MemoryManager().purge() # Speicher zurücksetzen
pq = PriorityQueue(Literal(size))
insert_list = [random.randint(-100, 100) for _ in range(size)]
if presorted:
insert_list.sort()
for insert_value in insert_list:
pq.insert(MemoryCell(insert_value))
MemoryManager().reset()
pq.pop()
MemoryManager.save_stats(size)
MemoryManager.plot_stats(["cells", "compares", "writes"])
if __name__ == '__main__':
length = Literal(10)
pq = PriorityQueue(length)
for i in range(10):
space_left = int(length) - len(pq)
if space_left > 0:
insert_count = random.randint(1, space_left)
insert_sequence = [random.randint(1, int(length)) for _ in range(insert_count)]
print(f"-> {insert_sequence}")
for j in insert_sequence:
pq.insert(MemoryCell(j))
print(f"{pq}")
if not pq.is_empty():
pop_count = random.randint(1, len(pq))
output_sequence = [int(pq.pop()) for _ in range(pop_count)]
print(f"<- {output_sequence}")
print(f"{pq}")
sizes = range(10, 501, 5)
analyze_complexity_insert(sizes, presorted=True)
analyze_complexity_pop(sizes, presorted=True)

View File

@ -1,93 +0,0 @@
from utils.memory_array import MemoryArray
from utils.memory_cell import MemoryCell
from utils.memory_manager import MemoryManager
from utils.literal import Literal
def quick_sort_stepwise(z: MemoryArray, l: Literal, r: Literal):
if l < r:
q = partition(z, l, r)
yield z
yield from quick_sort_stepwise(z, l, q.pred())
yield from quick_sort_stepwise(z, q.succ(), r)
yield z
def partition(z: MemoryArray, l: Literal, r: Literal):
p = mid_index(z, l, r, Literal((int(l)+int(r))//2))
swap(z, p, r)
with MemoryCell(z[r]) as pivot, MemoryCell(l) as i, MemoryCell(r.pred()) as j:
while i < j:
while z[i] < pivot:
i.set(i.succ())
while j > l and z[j] >= pivot:
j.set(j.pred())
if i < j:
swap(z, int(i), int(j))
i.set(i.succ())
j.set(j.pred())
if i == j and z[i] < pivot:
i.set(i.succ())
if z[i] != pivot:
swap(z, int(i), int(r))
return Literal(i)
def mid_index(z: MemoryArray, i1, i2, i3):
if z[i1] < z[i2] < z[i3]:
return i2
elif z[i3] < z[i2] < z[i1]:
return i2
elif z[i2] < z[i1] < z[i3]:
return i1
elif z[i3] < z[i1] < z[i2]:
return i1
else:
return i3
def quick_sort(z: MemoryArray, l: Literal = None, r: Literal = None):
if l is None:
l = Literal(0)
if r is None:
r = z.length().pred()
sort_generator = quick_sort_stepwise(z, l, r)
while True:
try:
next(sort_generator)
except StopIteration:
break
def sort_file(filename, sort_func):
z = MemoryArray.create_array_from_file(filename)
sort_func(z)
return z
def analyze_complexity(sort_func, sizes, presorted=False):
"""
Analysiert die Komplexität einer Sortierfunktion.
:param sort_func: Die Funktion, die analysiert wird.
:param sizes: Eine Liste von Eingabegrößen für die Analyse.
"""
for size in sizes:
MemoryManager.purge() # Speicher zurücksetzen
if presorted:
random_array = MemoryArray.create_sorted_array(size)
else:
random_array = MemoryArray.create_random_array(size, -100, 100)
sort_func(random_array)
MemoryManager.save_stats(size)
MemoryManager.plot_stats(["cells", "compares", "writes"])
def swap(z: MemoryArray, i: int, j: int):
tmp = z[Literal(i)].value
z[Literal(i)] = z[Literal(j)]
z[Literal(j)].set(tmp)
if __name__ == '__main__':
sizes = range(10, 101, 5)
analyze_complexity(quick_sort, sizes)
analyze_complexity(quick_sort, sizes, True)

View File

@ -1,15 +0,0 @@
from utils.memory_cell import MemoryCell
class BinaryTreeNode(MemoryCell):
def __init__(self, value):
super().__init__(value)
self.left = None
self.right = None
def __repr__(self):
return f"BinaryTreeNode(value={self.value}, left={self.left}, right={self.right})"
def __str__(self):
return str(self.value)

View File

@ -1,12 +0,0 @@
from utils.memory_array import MemoryArray
from vorlesung.L05_binaere_baeume.avl_tree import AVLTree
if __name__ == "__main__":
a = MemoryArray.create_array_from_file("data/seq0.txt")
tree = AVLTree()
for cell in a:
tree.insert(int(cell))
tree.graph_traversal()

View File

@ -1,12 +0,0 @@
from utils.memory_array import MemoryArray
from vorlesung.L05_binaere_baeume.bin_tree import BinaryTree
if __name__ == "__main__":
a = MemoryArray.create_array_from_file("data/seq0.txt")
tree = BinaryTree()
for cell in a:
tree.insert(int(cell))
tree.graph_traversal()

View File

@ -1,106 +0,0 @@
import math
import unittest
from utils.literal import Literal
from utils.memory_cell import MemoryCell
from utils.memory_array import MemoryArray
from vorlesung.L07_hashtable.hashtable import HashTableOpenAddressing
#Goldener Schnitt
a = Literal((math.sqrt(5) - 1) / 2)
# Hashfunktion nach multiplikativer Methode
def h(x: MemoryCell, m: Literal) -> Literal:
with MemoryCell(int(x * a)) as integer_part, MemoryCell(x * a) as full_product:
with MemoryCell(full_product - integer_part) as fractional_part:
return Literal(abs(int(fractional_part * m)))
# Quadratische Sondierung
def f(x: MemoryCell, i: Literal, m: Literal) -> Literal:
c1 = 1
c2 = 5
with MemoryCell(h(x, m)) as initial_hash, MemoryCell(c2 * int(i) * int(i)) as quadratic_offset:
with MemoryCell(initial_hash + quadratic_offset) as probe_position:
probe_position += Literal(c1 * int(i)) # Linear component
return probe_position % m
# Symmetrische quadratische Sondierung
def fs(x: MemoryCell, i: Literal, m: Literal) -> Literal:
with MemoryCell(h(x, m)) as base_hash, MemoryCell(int(i) * int(i)) as square:
if int(i) % 2 == 0: # gerades i: Vorwärtssondierung
with MemoryCell(base_hash + square) as position:
return position % m
else: # ungerades i: Rückwärtssondierung
with MemoryCell(base_hash - square) as position:
return position % m
if __name__ == "__main__":
print("*** Aufgabe 3 ***")
size = Literal(20)
print(f"Anlage einer Hash-Tabelle mit offener Adressierung mit Größe {size}")
ht = HashTableOpenAddressing(size, f)
print("Einfügen der Werte aus seq0.txt")
for cell in MemoryArray.create_array_from_file("data/seq0.txt"):
if not ht.insert(cell):
print(f"Einfügen von {cell} nicht möglich")
print(ht)
print(f"Belegungsfaktor: {ht.alpha()}")
with MemoryCell(52) as cell:
print(f"Suche nach {cell}")
if ht.search(cell):
print(f"{cell} gefunden, wird gelöscht.")
ht.delete(cell)
else:
print(f"{cell} nicht gefunden")
print(ht)
print(f"Belegungsfaktor: {ht.alpha()}")
print("Einfügen von 24")
with MemoryCell(24) as cell:
if not ht.insert(cell):
print(f"Einfügen von {cell} nicht möglich")
print(ht)
print(f"Belegungsfaktor: {ht.alpha()}")
print()
print("*** Aufgabe 4 ***")
size = Literal(90)
print(f"Anlage einer Hash-Tabelle mit offener Adressierung mit Größe {size}")
ht = HashTableOpenAddressing(size, f)
print("Einfügen der Werte aus seq1.txt")
for cell in MemoryArray.create_array_from_file("data/seq1.txt"):
if not ht.insert(cell):
print(f"Einfügen von {cell} nicht möglich")
print(ht)
print(f"Belegungsfaktor: {ht.alpha()}")
print()
print("*** Aufgabe 5 ***")
size = Literal(89)
print(f"Anlage einer Hash-Tabelle mit offener Adressierung mit Größe {size}")
ht = HashTableOpenAddressing(size, f)
print("Einfügen der Werte aus seq1.txt")
for cell in MemoryArray.create_array_from_file("data/seq1.txt"):
if not ht.insert(cell):
print(f"Einfügen von {cell} nicht möglich")
print(ht)
print(f"Belegungsfaktor: {ht.alpha()}")
print()
print("*** Aufgabe 6 ***")
size = Literal(90)
print(f"Anlage einer Hash-Tabelle mit offener Adressierung mit Größe {size}")
print("Verwendung der symmetrischen quadratischen Sondierung")
ht = HashTableOpenAddressing(size, fs)
print("Einfügen der Werte aus seq1.txt")
for cell in MemoryArray.create_array_from_file("data/seq1.txt"):
if not ht.insert(cell):
print(f"Einfügen von {cell} nicht möglich")
print(ht)
print(f"Belegungsfaktor: {ht.alpha()}")
print()

View File

@ -1,37 +0,0 @@
import re
from utils.project_dir import get_path
from vorlesung.L08_graphen.graph import Graph, AdjacencyListGraph, AdjacencyMatrixGraph
def read_cave_into_graph(graph: Graph, filename: str):
"""Read a cave description from a file and insert it into the given graph."""
filename = get_path(filename)
with open(filename, "r") as file:
lines = file.readlines()
for line in lines:
# match a line with two node names and an optional direction
m = re.match(r"(^\s*\"(.*)\"\s*([<>]*)\s*\"(.*)\"\s*)", line)
if m:
startnode = m.group(2)
endnode = m.group(4)
opcode = m.group(3)
graph.insert_vertex(startnode)
graph.insert_vertex(endnode)
if '>' in opcode:
graph.connect(startnode, endnode)
if '<' in opcode:
graph.connect(endnode, startnode)
graph = AdjacencyListGraph()
# graph = AdjacencyMatrixGraph()
read_cave_into_graph(graph, "data/hoehle.txt")
_, predecessor_map = graph.bfs('Höhleneingang')
path = graph.path('Schatzkammer', predecessor_map)
print(path)
_, predecessor_map = graph.bfs('Schatzkammer')
path = graph.path('Höhleneingang', predecessor_map)
print(path)
graph.graph("Höhle")

View File

@ -1,59 +0,0 @@
from utils.project_dir import get_path
from vorlesung.L08_graphen.graph import AdjacencyListGraph
DIRECTIONS = [(1,0), (0, 1), (-1, 0), (0, -1)]
class D16Solution:
def __init__(self):
with open(get_path("data/aoc2416.txt"), "r") as file:
self.puzzle = [line.strip() for line in file]
self.cells = set()
self.start = None
self.end = None
def get_cells_start_end(self):
for row in range(len(self.puzzle)):
for col in range(len(self.puzzle[row])):
if self.puzzle[row][col] != '#':
self.cells.add((col, row))
if self.puzzle[row][col] == 'S':
self.start = (col, row)
if self.puzzle[row][col] == 'E':
self.end = (col, row)
def get_label(self, cell, direction):
"""Generate a label for a cell based on its coordinates and direction."""
return f"{cell[0]},{cell[1]}_{direction}"
def create_graph(self):
graph = AdjacencyListGraph()
for cell in self.cells:
for direction in DIRECTIONS:
label = self.get_label(cell, direction)
graph.insert_vertex(label)
for cell in self.cells:
for d, direction in enumerate(DIRECTIONS):
label = self.get_label(cell, direction)
dx, dy = direction
neighbor = (cell[0] + dx, cell[1] + dy)
if neighbor in self.cells:
graph.connect(label, self.get_label(neighbor, direction))
direction_left = DIRECTIONS[(d - 1) % 4]
direction_right = DIRECTIONS[(d + 1) % 4]
graph.connect(label, self.get_label(cell, direction_left), 1000)
graph.connect(label, self.get_label(cell, direction_right), 1000)
return graph
if __name__ == "__main__":
solution = D16Solution()
solution.get_cells_start_end()
graph = solution.create_graph()
start = solution.get_label(solution.start, DIRECTIONS[0])
print(f"Start: {start}")
distance_map, predecessor_map = graph.dijkstra(start)
end_labels = [solution.get_label(solution.end, direction) for direction in DIRECTIONS]
end_vertices = [graph.get_vertex(label) for label in end_labels]
min_weight = min([distance_map[vertex] for vertex in end_vertices])
print(f"Minimum distance to End {solution.end}: {min_weight}")

View File

@ -1,32 +0,0 @@
from vorlesung.L08_graphen.graph import Graph, AdjacencyMatrixGraph
from utils.project_dir import get_path
import re
def read_elektro_into_graph(graph: Graph, filename: str):
pattern = re.compile(r'"([^"]+)";"([^"]+)";(\d+)')
with (open(filename, "r") as file):
for line in file:
m = pattern.match(line)
if m:
start_name = m.group(1)
end_name = m.group(2)
cost = int(m.group(3))
graph.insert_vertex(start_name)
graph.insert_vertex(end_name)
graph.connect(start_name, end_name, cost)
graph.connect(end_name, start_name, cost)
if __name__ == "__main__":
graph = AdjacencyMatrixGraph()
read_elektro_into_graph(graph, get_path("data/elektro.txt"))
parents, cost = graph.mst_prim()
print(f"Kosten nach Prim: {cost}")
for node, parent in parents.items():
if parent is not None:
print(f"{node} - {parent}")
edges, cost = graph.mst_kruskal()
print(f"Kosten nach Kruskal: {cost}")
for start_name, end_name, _ in edges:
print(f"{start_name} - {end_name}")

View File

@ -1,4 +1,3 @@
matplotlib
numpy
pygame
graphviz

View File

@ -107,7 +107,7 @@ def partitionIterative(arr : MemoryArray, l : Literal, h : Literal, mode=0):
# Carefull that we do not use a reference. I suppose python would return one here if we just assign without value>Literal cast.
# At least this helped fix weird issue
pivotValue : Literal = arr[h]
pivotValue : Literal = Literal(arr[h].value)
i : MemoryCell = MemoryCell(l.pred())
for j in mrange(l, h):
@ -115,7 +115,7 @@ def partitionIterative(arr : MemoryArray, l : Literal, h : Literal, mode=0):
i += Literal(1) # increment index of smaller element
swap(arr, int(i), int(j))
swap(arr, i.succ().value, h.value)
swap(arr, int(i.succ()), int(h))
return i.succ()
def LEGACY_quickSort(z: MemoryArray, l: Literal = Literal(0), r: Literal = Literal(-1), mode=0):
@ -185,6 +185,6 @@ if __name__ == '__main__':
print(filename)
toSort = MemoryArray.create_array_from_file(filename)
timeMS(quickSortIterative, toSort, Literal(0), toSort.length().pred(), mode=1)
print(toSort)
# print(toSort)
print("Kann durch die Modifikation eine besser Laufzeit als nlog(n) erreicht werden? Nein! nlog(n) ist das Minimum. Durch die Änderung kann aber der Worst-Case fall von n^2 für z.B. bereits vorsortierte Arrays oder Arrays mit vielen Duplikaten vermieden werden.")

View File

@ -1,293 +0,0 @@
import logging
logger = logging.getLogger(__name__)
# logging.basicConfig(level=logging.DEBUG)
import time
def timeMS(func, *args, **kwargs):
startTime = time.perf_counter()
result = func(*args, **kwargs)
endTime = time.perf_counter()
elapsedMS = (endTime - startTime) * 1000 # Convert to milliseconds
print(f"{func.__name__} took {elapsedMS:.2f} ms")
return result
from utils.memory_array import MemoryArray
from utils.memory_cell import MemoryCell
from utils.literal import Literal
from utils.constants import MAX_VALUE
from utils.memory_manager import MemoryManager
from utils.memory_range import mrange
# Impl of MemoryArray says we cant add our own Datatypes beside Literal and List
# BUUUUT we can just wrap our Datatype in a List :-)
# We store them in a MemoryArray internaly tho anyhow so we increment our Counters for the RAM
class HeapEntry:
def __init__(self, item, priority=1):
self.data = MemoryArray(Literal(2))
# 0: Content, 1: Prio
self.data[Literal(0)] = Literal(item)
self.data[Literal(1)] = Literal(priority)
def getItem(self):
return self.data[Literal(0)]
def getPriority(self):
return self.data[Literal(1)]
def setPriority(self, priority):
self.data[Literal(1)] = Literal(priority)
def __lt__(self, other):
if other is None:
return True
if isinstance(other, (int, float)):
return self.getPriority().value > other
return self.getPriority() > other.getPriority()
def __gt__(self, other):
if other is None:
return False
if isinstance(other, (int, float)):
return self.getPriority().value < other
return self.getPriority() < other.getPriority()
def __eq__(self, other):
return self.getPriority() == other.getPriority()
def __str__(self):
return f"({self.getItem()}, prio={self.getPriority()})"
class PriorityQueue:
def __init__(self, max_size : Literal = Literal(100)):
self.heap = MemoryArray(max_size)
# Add uninitialized HeapEntry Values so the Adds/Compares do not fail on emtpy stack.
# Would have to switch to MIN_VALUE if we switch what is a "Higher" Prio
for i in mrange(max_size.value):
self.heap[i].set([HeapEntry(MAX_VALUE, MAX_VALUE)])
self.size = MemoryCell(0)
def parent(self, i: Literal) -> Literal:
return MemoryCell(i.pred()) // Literal(2)
def leftChild(self, i: Literal) -> Literal:
return MemoryCell(MemoryCell(2) * i) + Literal(1)
def rightChild(self, i: Literal) -> Literal:
return MemoryCell(MemoryCell(2) * i) + Literal(2)
# Swap the Lists -> Therefore get the value which is the List and then Set it again
def swap(self, i: Literal, j: Literal):
tmp_i = self.heap[i].value
tmp_j = self.heap[j].value
self.heap[i].set(tmp_j)
self.heap[j].set(tmp_i)
def maxHeapify(self, i: Literal):
left = self.leftChild(i)
right = self.rightChild(i)
largest = i
if left < Literal(self.size.value) and self.heap[left].value[0] > self.heap[largest].value[0]:
largest = left
if right < Literal(self.size.value) and self.heap[right].value[0] > self.heap[largest].value[0]:
largest = right
if largest != i:
self.swap(i, largest)
self.maxHeapify(largest)
def insert(self, entry : HeapEntry):
if self.size >= self.heap.length():
raise IndexError("Heap full")
i = self.size
self.heap[i].set([entry])
while i > Literal(0) and self.heap[self.parent(i)].value[0] < self.heap[i].value[0]:
self.swap(i, self.parent(i))
i = self.parent(i)
self.size += Literal(1)
def pop(self):
if self.isEmpty():
raise IndexError("Queue is empty!")
max_item = self.heap[Literal(0)].value[0]
self.heap[Literal(0)] = self.heap[self.size - Literal(1)]
self.size -= Literal(1)
self.maxHeapify(Literal(0))
return max_item
def peek(self):
if self.isEmpty():
raise IndexError("Queue is empty")
return self.heap[Literal(0)].value[0]
def isEmpty(self):
return self.size == Literal(0)
def __len__(self):
return self.size
def __str__(self):
entries = []
for i in mrange(self.size.value):
entry = self.heap[i].value[0]
if entry.getItem() != MAX_VALUE:
entries.append(str(entry))
return "[" + ", ".join(entries) + "]"
# Insert here so we dont run into import problems, but can deliver this file Standalone
class BinaryTreeNode(MemoryCell):
def __init__(self, value):
super().__init__(value)
self.left = None
self.right = None
def __repr__(self):
return f"BinaryTreeNode(value={self.value}, left={self.left}, right={self.right})"
def __str__(self):
return str(self.value)
class BinaryTree:
def __init__(self):
self.root: BinaryTreeNode | None = None
def insert(self, value: BinaryTreeNode):
# Insert at Leaf, if smaller then left one, otherwise right one
def _insert(node: BinaryTreeNode | None, value) -> BinaryTreeNode:
if node is None:
return BinaryTreeNode(value)
if value < node:
node.left = _insert(node.left, value) # type: ignore -> Ignoring pywright errors
else:
node.right = _insert(node.right, value) # type: ignore -> Ignoring pywright errors
return node
self.root = _insert(self.root, value)
def traverse(self, mode="in", visual=False):
mode = mode.lower()
# Have internal depth counting
def InternalTraverse(node, prefix="", is_left=True, depth=0):
if node is None:
return [] if not visual else []
result = []
node_str = str(node)
prefixAcc = prefix + ("| " if is_left and depth > 0 else " ")
if visual:
connector = "+-- " if is_left else "L-- "
line = prefix + connector + node_str if depth > 0 else node_str
result.append(line)
else:
result.append(node_str)
if mode == "pre":
result += InternalTraverse(node.left, prefixAcc, True, depth + 1)
result += InternalTraverse(node.right, prefixAcc, False, depth + 1)
elif mode == "in":
result += InternalTraverse(node.left, prefixAcc, True, depth + 1)
result += InternalTraverse(node.right, prefixAcc, False, depth + 1)
elif mode == "post":
result += InternalTraverse(node.left, prefixAcc, True, depth + 1)
result += InternalTraverse(node.right, prefixAcc, False, depth + 1)
return result
if self.root is None:
return "(empty tree)" if visual else []
result = InternalTraverse(self.root)
return "\n".join(result) if visual else result
def levelOrderWithPriorityQueue(self):
if not self.root:
return []
# Create a priority queue, using a reduced prio for every new entry -> behaviour as regular queue FIFO
pq = PriorityQueue(Literal(1000))
# Again we cannot create a MemoryArray of dynamic sizes and also cannot create a string as MemoryCell does not like it
# Again we just create a list holding a single dummy Entry (to set its size to 1) and then just use this "list" as our string
# Appending to it is easy as it is just a regular list and in the end we return it
# Like MemoryCell("").value.append("STRING") will fail. But list-wrap works.
#
# Sorry for Syntax, dont know any better way to have everything as RAM-Managed memory:-(
result = MemoryArray(["MYSTRING"])
result[Literal(0)].set([]);
counter = MemoryCell(0)
def nextPriority():
val = counter.value
counter.set(Literal(val + 1))
return val
pq.insert(HeapEntry([self.root], nextPriority()))
while not pq.isEmpty():
entry = pq.pop()
node = entry.getItem().value
result[Literal(0)].value.append(str(node[0]))
if node[0].left:
pq.insert(HeapEntry([node[0].left], nextPriority()))
if node[0].right:
pq.insert(HeapEntry([node[0].right], nextPriority()))
return result[Literal(0)]
def __str__(self):
return str(self.traverse(mode="PrE", visual=True))
def analyze_complexity(fn, sizes):
"""
Analysiert die Komplexität einer maximalen Teilfolgenfunktion.
:param max_sequence_func: Die Funktion, die analysiert wird.
:param sizes: Eine Liste von Eingabegrößen für die Analyse.
"""
for size in sizes:
MemoryManager.purge() # Speicher zurücksetzen
random_array = MemoryArray.create_random_array(size, -100, 100)
fn(random_array, Literal(0), random_array.length().pred())
MemoryManager.save_stats(size)
MemoryManager.plot_stats(["cells", "adds", "compares", "reads", "writes"])
if __name__ == '__main__':
# For debug, assert if working and complexity-analysis
# example()
print("Sorry for the Syntax and the large file, tried to keep everything as a standalone file to help make it \" download and run \".\n \
Also did - once again - not find a better way to have a queue managed by the RAM contain the values of non-integer-attributes I \n\
needed it to. Therefore i reused my Priorityqueue and its accesses via the unspecified wrapped list.");
# for filename in ["data/seq0.txt", "data/seq1.txt", "data/seq2.txt" ,"data/seq3.txt"]:
for filename in [ "data/seq0.txt"]:
print(filename)
binTreeData = MemoryArray.create_array_from_file(filename)
binTree = BinaryTree()
for value in binTreeData:
binTree.insert(BinaryTreeNode(value))
# Print overlaoded InOrder traversal
print(binTree)
# print(binTree.traverse(mode="pre", visual=False))
# print(binTree.traverse(mode="in", visual=False))
# print(binTree.traverse(mode="post", visual=False))
# Print Levelorder traversal:
print(binTree.levelOrderWithPriorityQueue())

View File

@ -1,246 +0,0 @@
import logging
logger = logging.getLogger(__name__)
# logging.basicConfig(level=logging.DEBUG)
import time
def timeMS(func, *args, **kwargs):
startTime = time.perf_counter()
result = func(*args, **kwargs)
endTime = time.perf_counter()
elapsedMS = (endTime - startTime) * 1000 # Convert to milliseconds
print(f"{func.__name__} took {elapsedMS:.2f} ms")
return result
from utils.memory_array import MemoryArray
from utils.literal import Literal
from utils.memory_manager import MemoryManager
from vorlesung.L05_binaere_baeume.bin_tree import BinaryTree
from vorlesung.L05_binaere_baeume.bin_tree_node import BinaryTreeNode
def analyze_complexity(fn, sizes):
"""
Analysiert die Komplexität einer maximalen Teilfolgenfunktion.
:param max_sequence_func: Die Funktion, die analysiert wird.
:param sizes: Eine Liste von Eingabegrößen für die Analyse.
"""
for size in sizes:
MemoryManager.purge() # Speicher zurücksetzen
random_array = MemoryArray.create_random_array(size, -100, 100)
fn(random_array, Literal(0), random_array.length().pred())
MemoryManager.save_stats(size)
MemoryManager.plot_stats(["cells", "adds", "compares", "reads", "writes"])
lineAccumulator = []
# Returnvalue does not get forwarded so we can not work with return.
# Will try glob vars to append the string
# Signature: def print_node(node, indent=0, line=None):
def clbk_graphvizify(toDecorate : BinaryTreeNode, indent=0, line=None):
global lineAccumulator
if isinstance(toDecorate, AVLTreeNode):
lineAccumulator.append(f'n_{id(toDecorate)} [label=<{toDecorate.value}<BR/><FONT COLOR="RED" POINT-SIZE="10.0" FACE="ambrosia">B: {toDecorate.balanceFactor}</FONT>>]')
else:
lineAccumulator.append(f"n_{id(toDecorate)} [label={toDecorate.value}]")
# Create edges for nodes with Child (use l - r)
if toDecorate.left is not None:
lineAccumulator.append(f"n_{id(toDecorate)} -> n_{id(toDecorate.left)}")
if toDecorate.right is not None:
lineAccumulator.append(f"n_{id(toDecorate)} -> n_{id(toDecorate.right)}")
def graphvizify() -> str:
# Header
result = "digraph {\n\t"
# Body
result += ('\n\t'.join(str(item) for item in lineAccumulator))
# Footer
result += "\n}"
return result
class AVLTreeNode(BinaryTreeNode):
def __init__(self, value):
super().__init__(value)
self.parentRef = None
# Start balanced as we probably have no children right after insert
self.balanceFactor = Literal(0)
def rightRotate(self, node) -> 'AVLTreeNode|None':
if node is None:
return None
oLeft = node.left;
oLeft.parentRef = node.parentRef;
node.left = oLeft.right;
if node.left is not None:
node.left.parentRef = node;
oLeft.right = node;
node.parentRef = oLeft;
if oLeft.parentRef is not None:
if oLeft.parentRef.right is node:
oLeft.parentRef.right = oLeft;
elif oLeft.parentRef.left is node:
oLeft.parentRef.left = oLeft;
node.getSetBalanceFactor()
oLeft.getSetBalanceFactor()
return oLeft
def leftRotate(self, node) -> 'AVLTreeNode|None':
if node is None:
return None
oRight = node.right
oRight.parentRef = node.parentRef
node.right = oRight.left
if node.right is not None:
node.right.parentRef = node
oRight.left = node
node.parentRef = oRight
if oRight.parentRef is not None:
if oRight.parentRef.right is node:
oRight.parentRef.right = oRight
elif oRight.parentRef.left is node:
oRight.parentRef.left = oRight
node.getSetBalanceFactor()
oRight.getSetBalanceFactor()
return oRight
def getSetBalanceFactor(self) -> Literal:
leftHeight = self.left.height() if self.left else 0
rightHeight = self.right.height() if self.right else 0
self.balanceFactor = Literal(rightHeight - leftHeight)
return self.balanceFactor
def rightLeftRotate(self, node) -> 'AVLTreeNode|None':
node.right = self.rightRotate(node.right)
return self.leftRotate(node)
def leftRightRotate(self, node) -> 'AVLTreeNode|None':
node.left = self.leftRotate(node.left)
return self.rightRotate(node)
def debugTraverse(node, source=1):
if node is None:
return None
logger.debug(f"{node.value} {node.getSetBalanceFactor()} {source}")
debugTraverse(node.left, 10);
debugTraverse(node.right, 20);
class AVLTree(BinaryTree):
# @override
def new_node(self, value) -> AVLTreeNode:
return AVLTreeNode(value)
def balanceAVLTree(self, node : AVLTreeNode):
# balance < -1 means imbalance to the left, > 1 means imbalance to the right
logger.debug("in")
if node is None:
return None
logger.debug("out")
node.getSetBalanceFactor()
logger.debug(f"Parent Balancing for {node.value} -> {node.balanceFactor} {node.left.height() if node.left else None} and {node.right.height() if node.right else None}")
# imbalance to left -> If we enter this we cannot LOGICALLY have a left=None node -> No need to chekc
if node.balanceFactor < Literal(-1):
# Left-Left
if node.left.balanceFactor <= Literal(0): # type: ignore -> Ignoring pywright error, see comment above
# Wow, this syntax is sketchy ^^
# TODO Maybe declare as static if python supports this? Or just leaf param be?
logger.debug("rr")
node = node.rightRotate(node)
# Left-Right
else:
# TODO Maybe declare as static if python supports this? Or just leaf param be?
logger.debug("lrr")
node = node.leftRightRotate(node)
# Right heavy
# imbalance to right -> If we enter this we cannot LOGICALLY have a right=None node -> No need to chekc
if node.balanceFactor > Literal(1):
# Right-Right case
if node.right.balanceFactor >= Literal(0): # type: ignore -> Ignoring pywright error, see comment above
# TODO Maybe declare as static if python supports this? Or just leaf param be?
logger.debug("lr")
node = node.leftRotate(node)
# Right-Left case
else:
# TODO Maybe declare as static if python supports this? Or just leaf param be?
logger.debug("rlr")
node = node.rightLeftRotate(node)
logger.debug(f"Reached {node.parentRef}")
if node.parentRef is not None:
logger.debug(f"Calling again for {node.parentRef.value}");
self.balanceAVLTree(node.parentRef);
else:
self.root = node;
# Node is balanced
return node
# @override
def insert(self, value):
node, parent = super().insert(value)
# NOTE Python does not have a Problem with NOT tellin us that we override something important
# or something that does not exist.... This Makes for AWESOME debugging .... ... ...
node.parentRef = parent
if parent:
node = self.balanceAVLTree(node.parentRef)
return node, parent
if __name__ == '__main__':
tree = AVLTree()
### Force RR
# testData = [30, 20, 10];
# for value in testData:
# tree.insert(MemoryCell(value));
### Force LR
# testData = [10, 20, 30];
# for value in testData:
# tree.insert(MemoryCell(value));
### Force LRR
# testData = [30, 10, 20]
# for value in testData:
# tree.insert(MemoryCell(value))
### Force RLR
# testData = [10, 30, 20]
# for value in testData:
# tree.insert(MemoryCell(value))
# Force rebuild of our balanceFactor indices...
# debugTraverse(tree.root)
binTreeData = MemoryArray.create_array_from_file("data/seq0.txt")
for value in binTreeData:
tree.insert(value)
lineAccumulator.clear();
tree.in_order_traversal(clbk_graphvizify)
# tree.tree_structure_traversal(clbk_graphvizify)
print(graphvizify())

View File

@ -1,334 +0,0 @@
import logging
from graphviz import Digraph
logger = logging.getLogger(__name__)
# logging.basicConfig(level=logging.DEBUG)
import time
def timeMS(func, *args, **kwargs):
startTime = time.perf_counter()
result = func(*args, **kwargs)
endTime = time.perf_counter()
elapsedMS = (endTime - startTime) * 1000 # Convert to milliseconds
print(f"{func.__name__} took {elapsedMS:.2f} ms")
return result
from utils.memory_array import MemoryArray
from utils.memory_cell import MemoryCell
from utils.literal import Literal
from utils.memory_range import mrange
from utils.memory_manager import MemoryManager
# We often want to "dynamically" extend our array, but thats not really what it was intended for
# Therefore we write a function to do so reusably
def memArrayInsert(array: MemoryArray, position: Literal, value) -> MemoryArray:
logger.debug(f"Pre-Insert: {array}")
newSize : Literal = array.length().succ()
newArray = MemoryArray(newSize)
# Copy elements til position
for i in mrange(position):
newArray[i] = array[i]
# Insert new value with check for MemCell Type
newArray[position] = value if isinstance(value, MemoryCell) else MemoryCell(value)
for i in mrange(position.succ(), newSize):
newArray[i] = array[i.pred()]
logger.debug(f"Post-Insert: {array}")
return newArray
# Likewise for the Split
# Here we split the array at the position EXCLUSIVELY for the first MemoryArray
def memArraySplit(array: MemoryArray, position: Literal) -> tuple[MemoryArray, MemoryArray]:
leftSize = position
rightSize = MemoryCell(array.length()) - position
left = MemoryArray(leftSize)
right = MemoryArray(rightSize)
for i in mrange(leftSize):
left[i] = array[i]
for i in mrange(rightSize):
right[i] = array[Literal(i.value + position.value)]
return left, right
class BTreeNode(MemoryCell):
def __init__(self):
super().__init__(value=None)
self.value = MemoryArray([])
self.children = MemoryArray([])
self.leaf = True
def __str__(self):
return "( " + " ".join(str(val) for val in self.value) + " )"
def isLeaf(self):
return self.children.length() == Literal(0)
class BTree:
def __init__(self, order):
self.order = Literal(order)
self.root = BTreeNode()
def _insertNonFull(self, node, key):
if node.leaf:
i = node.value.length()
# pos for new Key
while i > Literal(0) and key < node.value[i.pred()]:
i = i.pred()
# insert key at pos using helper fkt
node.value = memArrayInsert(node.value, i, key)
else:
j = Literal(0)
while j < node.value.length() and node.value[j] < key:
j = j.succ()
child = node.children[j].value[0]
# Splt if full
if child.value.length() == Literal(2 * self.order.value - 1):
self._splitChild(node, j)
if key > node.value[j]:
j = j.succ()
child = node.children[j].value[0]
# insert rec in selected Child
self._insertNonFull(child, key)
def insert(self, key):
if not isinstance(key, MemoryCell):
key = MemoryCell(key)
rootRef = self.root
if rootRef.value.length() == MemoryCell(2 * self.order.value - 1):
newRoot = BTreeNode()
newRoot.leaf = False
newRoot.children = MemoryArray(["DUMMY"])
newRoot.children[Literal(0)].set([rootRef])
self._splitChild(newRoot, Literal(0))
self.root = newRoot
self._insertNonFull(newRoot, key)
else:
logger.debug("Inserting in non-full");
self._insertNonFull(rootRef, key)
def _splitChild(self, parent: BTreeNode, index: Literal):
child = parent.children[index].value[0]
newRight = BTreeNode()
newRight.leaf = child.leaf
# median index
mid = Literal(self.order.value - 1)
medianKey = child.value[mid]
# Childs keys in l and r
leftKeys, rightKeys = memArraySplit(child.value, mid)
child.value = leftKeys
newRight.value = MemoryArray(rightKeys.length().pred())
for j in mrange(rightKeys.length().pred()):
newRight.value[j] = rightKeys[j.succ()]
# if child is not leaf distribute itschildren
if not child.leaf:
leftChildren, rightChildren = memArraySplit(child.children, mid.succ())
child.children = leftChildren
newRight.children = rightChildren
# Insert median key in parent and insert new right as i+1's chld
parent.value = memArrayInsert(parent.value, index, medianKey)
parent.children = memArrayInsert(parent.children, index.succ(), [newRight])
def search(self, key) -> BTreeNode:
return BTreeNode()
# Depth-Search
def _traversalInOrder(self, node : BTreeNode, result):
logger.debug(type(node.value))
logger.debug(node.value)
for i in mrange(node.value.length()):
# RecTerm
if not node.isLeaf():
self._traversalInOrder(node.children[i].value[0], result)
result.append(str(node.value[i]))
# RecTerm
if not node.isLeaf():
self._traversalInOrder(node.children[Literal(len(node.value))].value[0], result)
def structureTraversal(self, callback):
def traverse(node):
if node is None:
return
callback(node)
if not node.isLeaf():
for i in range(len(node.children)):
child = node.children[Literal(i)].value[0]
traverse(child)
traverse(self.root)
def traversal(self) -> list:
resultAcc = []
self._traversalInOrder(self.root, resultAcc)
return resultAcc
def search(self, searchVal : Literal) -> BTreeNode|None:
if self.root is None:
return None
current = self.root
while not current.isLeaf():
# Exit early if we are already way to large for our current Node. Should improve runtime
if searchVal > current.value[current.value.length().pred()]:
current = current.children[current.value.length()].value[0]
continue
# Go thru every value in the Node until we find anything
i = MemoryCell(0)
while i < current.value.length() and searchVal > current.value[i]:
i = i.succ()
# return exact match
if i < current.value.length() and searchVal == current.value[i]:
return current
# go to appropriate child
# If searchVal smaller than first value (i=0) -> leftmost child
# if searchVal larger than all values (i=len) -> rightmost child
# Otherwise -> child between values
current = current.children[Literal(i)].value[0]
# Final check in leaf node
for i in mrange(current.value.length()):
if searchVal == current.value[i]:
return current
return None
def height(self) -> Literal:
if self.root is None:
return Literal(0)
current = self.root
height = MemoryCell(1)
while not current.isLeaf():
height = height.succ()
current = current.children[Literal(0)].value[0]
return height
def clbk_graphvizify(toDecorate: BTreeNode, indent=0, line=None):
global dotAcc
values_str = "|".join(str(val) for val in toDecorate.value)
dotAcc.node(f'n_{id(toDecorate)}', values_str, shape='record')
# Create edges for all children
if not toDecorate.isLeaf():
for i in mrange(toDecorate.children.length()):
child = toDecorate.children[i].value[0]
dotAcc.edge(f'n_{id(toDecorate)}', f'n_{id(child)}')
def visualizeBTree(tree: BTree, filename='build/schoeffel_btree'):
try:
import graphviz
except ImportError:
raise AssertionError("Graphviz installed? Try commenting visualizeBTree or install 'pip install graphviz'")
global dotAcc
dotAcc = Digraph()
dotAcc.attr(rankdir='TB')
dotAcc.attr('node', shape='record', style='filled', fillcolor='lightgray')
dotAcc.attr('edge', arrowsize='0.5')
tree.structureTraversal(clbk_graphvizify)
try:
dotAcc.render(filename, view=True)
except Exception as e:
print(f"Could not display graph: {e}")
print("Saving graph file without viewing (Running WSL?)")
try:
dotAcc.render(filename, view=False)
except Exception as e:
print(f"Could not save graph file: {e}")
def graphvizify() -> str:
result = """digraph {
rankdir=TB;
node [shape=record, style=filled, fillcolor=lightgray];
edge [arrowsize=0.5];
"""
# Body
result += '\n\t'.join(str(item) for item in dotAcc)
# Footer
result += "\n}"
return result
def analyze_complexity(fn, sizes):
"""
Analysiert die Komplexität einer maximalen Teilfolgenfunktion.
:param max_sequence_func: Die Funktion, die analysiert wird.
:param sizes: Eine Liste von Eingabegrößen für die Analyse.
"""
for size in sizes:
MemoryManager.purge() # Speicher zurücksetzen
random_array = MemoryArray.create_random_array(size, -100, 100)
for value in random_array:
fn(value)
MemoryManager.save_stats(size)
MemoryManager.plot_stats(["cells", "compares", "reads", "writes"])
if __name__ == '__main__':
tree = BTree(order=3)
tree.insert(Literal(10));
tree.insert(Literal(11));
tree.insert(Literal(12));
print(tree.traversal());
binTreeData = MemoryArray.create_array_from_file("data/seq0.txt")
j = 0
for value in binTreeData:
tree.insert(value)
j = j +1
# Uncomment to view progress in insertion at every step saved as PDF
# visualizeBTree(tree, f"build/schoeffel_btree{j}")
logger.debug(tree.root.children)
# Graphvizify Wrapper
visualizeBTree(tree)
print(f"InOrder Traversal: {tree.traversal()}")
print(tree.search(Literal(50)))
print(tree.height())
tree3 = BTree(order=3)
tree5 = BTree(order=5)
binTreeData = MemoryArray.create_array_from_file("data/seq2.txt")
for value in binTreeData:
tree3.insert(value)
tree5.insert(value)
print(f"Order three for Seq2 produces height {tree3.height()}")
print(f"Order five for Seq2 produces height {tree5.height()}")
order3 = tree3.traversal()
order5 = tree5.traversal()
assert all(int(order3[i]) <= int(order3[i+1]) for i in range(len(order3)-1)), "Order3 not in ascending order"
assert all(int(order5[i]) <= int(order5[i+1]) for i in range(len(order5)-1)), "Order5 not in ascending order"
print(tree3.search(Literal(0)))
print(tree5.search(Literal(0)))
MemoryManager.purge()
analyze_complexity(tree3.insert, [10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
# tree.tree_structure_traversal(clbk_graphvizify)
# print(graphvizify())

View File

@ -1,266 +0,0 @@
import logging
logger = logging.getLogger(__name__)
# logging.basicConfig(level=logging.DEBUG)
import time
def timeMS(func, *args, **kwargs):
startTime = time.perf_counter()
result = func(*args, **kwargs)
endTime = time.perf_counter()
elapsedMS = (endTime - startTime) * 1000 # Convert to milliseconds
print(f"{func.__name__} took {elapsedMS:.2f} ms")
return result
from utils.memory_array import MemoryArray
from utils.memory_cell import MemoryCell
from utils.literal import Literal
from utils.memory_range import mrange
from utils.memory_manager import MemoryManager
def getHashFunction(m : Literal):
# Hash function using golden ratio
# Golden ratio (sqrt(5) - 1) / 2; Allowed to to this way as it is a one-time calc ^^
A : Literal = Literal((5 ** 0.5 - 1) / 2)
def hashFunctionGoldenRatio(key : Literal|MemoryCell) -> Literal:
if not isinstance(key, MemoryCell):
key = MemoryCell(key)
assert(isinstance(key, MemoryCell))
product : Literal = key * A
# discard decimal part
intPart = Literal(int(product.value))
fracPart = MemoryCell(product) - intPart
# Scale by m
hashVal = Literal(int(fracPart.value * m.value))
return hashVal
return hashFunctionGoldenRatio
# Probing function h + i + 5i^2
def getProbingFunction(hashFunc, m: Literal, probingMethod="quadratic"):
def quadraticProbe(key, i: Literal|MemoryCell):
if not isinstance(i, MemoryCell):
i = MemoryCell(i)
# TODO Can save operation/allocation of MemCEll here, but for better flow leave this way
hPrime_x = MemoryCell(hashFunc(key))
iSquared = MemoryCell(i * i)
result = MemoryCell(MemoryCell(hPrime_x + i) + iSquared * Literal(5)) % m
return result
def symmetricProbe(key, i: Literal|MemoryCell):
if not isinstance(i, MemoryCell):
i = MemoryCell(i)
hPrime_x = MemoryCell(hashFunc(key))
iSquared = MemoryCell(i * i)
if i % Literal(2) == Literal(0):
result = MemoryCell(hPrime_x + iSquared) % m
else:
result = MemoryCell(hPrime_x - iSquared) % m
return result
if probingMethod == "symmetric":
return symmetricProbe
else:
return quadraticProbe
class HashTable:
# marker for deleted entries
DELETED = MemoryCell("DELETED")
def __init__(self, size, probingMethod="quadratic"):
if not isinstance (size, Literal|MemoryCell):
size = Literal(size)
self.size = size
self.table = MemoryArray(self.size)
for i in mrange(self.size):
self.table[i].set(None)
self.count = Literal(0) # Count of actual elements
self.deletedCount = Literal(0) # Count of deleted slots
# Initialize hash and probe function
self.hashFunc = getHashFunction(self.size)
self.probe = getProbingFunction(self.hashFunc, self.size, probingMethod)
def insert(self, value):
if not isinstance(value, MemoryCell):
value = MemoryCell(value)
# Check if table is full (considering deleted entries asd well as normal count)
if (MemoryCell(self.count) + self.deletedCount) == self.size:
logger.info(f"Failed to insert {value} - table is full")
return False
i = Literal(0)
while i < self.size:
# Get our Index via the ProbingFkt
index = self.probe(value, i)
# Empty slot or deleted marker found
# Need the get here as we want to compare the value (none) to None.
# For the rest normal should be fine
if self.table[index].get() is None or self.table[index] == self.DELETED:
if self.table[index] == self.DELETED:
# Were on a cell that was deleted. Now we write in it, but decrease delCount
self.deletedCount = self.deletedCount.pred()
self.table[index] = value
self.count = self.count.succ() # Inc fillcounter
logger.debug(f"value {value} was inserted successfully at {index}, count is now at \
{self.count}|{self.deletedCount}");
return True
# Value already exists
# TODO DISCUSSION Wouldnt it defcato be a successfull insert if we are already in our hashmap? Maybe then return true here?
if self.table[index] == value:
logger.info(f"value {value} already exits in the table");
return False
i = i.succ()
# Couldn't find a slot even though count < size
logger.info(f"Failed to insert {value} - table is full")
return False
def search(self, value):
if not isinstance(value, MemoryCell):
value = MemoryCell(value)
i = Literal(0)
while i < self.size:
index = self.probe(value, i)
# Empty slot found - value doesn't exist
if self.table[index].get() is None:
return False
# Value found
if self.table[index] == value:
return True
# If deleted marker or different value, continue
i = i.succ()
return False
def delete(self, value):
if not isinstance(value, MemoryCell):
value = MemoryCell(value)
i = Literal(0)
while i < self.size:
index = self.probe(value, i)
# Empty slot found - value doesn't exist
if self.table[index].get() is None:
return False
# Value found - mark as deleted
if self.table[index] == value:
# TODO Check wheter it is .set() or = here
self.table[index].set(self.DELETED)
self.count = self.count.pred()
self.deletedCount = self.deletedCount.succ()
return True
i = i.succ()
return False
def __str__(self):
result = "["
for i in mrange(self.size):
if self.table[i].get() is None:
result += "None"
else:
result += str(self.table[i])
if i < self.size.pred():
result += ", "
result += "]"
return result
def alpha(self):
# load factor (count / size)
return Literal(self.count.value / self.size.value)
if __name__ == "__main__":
table = HashTable(20)
seq0Data = MemoryArray.create_array_from_file("data/seq0.txt")
print(f"Hash table before inserting seq0.txt: {table}")
print("Inserting values from seq0.txt...")
for value in seq0Data:
table.insert(value)
strFirst = str(table.table[Literal(0)])
# delete first 5 entries and then try to reinsert them
for i in mrange(5):
table.delete(seq0Data[i])
assert(table.deletedCount == Literal(5)), "Deleted count should be 5"
for i in mrange(5):
table.insert(seq0Data[i])
assert(table.deletedCount == Literal(0)), "Deleted count should be 0 after reinserting"
assert(strFirst == str(table.table[Literal(0)])), "First entry should be the same as before"
print(f"Hashtable after inserting seq0.txt: {table}")
print(f"Load factor after inserting: {table.alpha()}")
print("Deleting 52...")
table.delete(Literal(52))
print(f"Hash table after deletion: {table}")
print(f"New load factr: {table.alpha()}")
print("\nInserting value 24...")
table.insert(Literal(24))
print(f"Hash table after inserting 24: {table}")
table90 = HashTable(90)
seq1Data = MemoryArray.create_array_from_file("data/seq1.txt")
print(f"Inserting values from seq1.txt into table with size 90...")
insertedCount = Literal(0)
for value in seq1Data:
if table90.insert(value):
insertedCount = insertedCount.succ()
print(f"Successfully inserted {insertedCount} out of {Literal(len(seq1Data))} values")
print(f"Load factor: {table90.alpha()}")
table89 = HashTable(89)
print(f"Inserting values from seq1.txt into table with 89...")
insertedCount = Literal(0)
for value in seq1Data:
if table89.insert(value):
insertedCount = insertedCount.succ()
print(f"Successfully inserted {insertedCount} out of {Literal(len(seq1Data))} values")
print(f"Load factor: {table89.alpha()}")
tableSymmetric = HashTable(90, probingMethod="symmetric")
print(f"Inserting values from seq1.txt into table with size 90 and symmetric probing...")
insertedCount = Literal(0)
for value in seq1Data:
if tableSymmetric.insert(value):
insertedCount = insertedCount.succ()
print(f"Successfully inserted {insertedCount} out of {Literal(len(seq1Data))} values")
print(f"Load factor: {tableSymmetric.alpha()}")

View File

@ -1,124 +0,0 @@
import logging
from graphviz import Digraph
from collections import deque
logger = logging.getLogger(__name__)
# logging.basicConfig(level=logging.DEBUG)
import time
def timeMS(func, *args, **kwargs):
startTime = time.perf_counter()
result = func(*args, **kwargs)
endTime = time.perf_counter()
elapsedMS = (endTime - startTime) * 1000 # Convert to milliseconds
print(f"{func.__name__} took {elapsedMS:.2f} ms")
return result
from utils.memory_array import MemoryArray
from utils.memory_cell import MemoryCell
from utils.literal import Literal
from utils.memory_range import mrange
from utils.memory_manager import MemoryManager
class Graph:
def __init__(self):
self.adjacencyList = {}
def addEdge(self, node1, node2, bidirectional=True):
if node1 not in self.adjacencyList:
self.adjacencyList[node1] = []
if node2 not in self.adjacencyList:
self.adjacencyList[node2] = []
self.adjacencyList[node1].append(node2)
if bidirectional:
self.adjacencyList[node2].append(node1)
def serialize(self):
return self.adjacencyList
def breadthFirstSearch(self, start, goal, edgesGonePassed = None):
if start not in self.adjacencyList or goal not in self.adjacencyList:
return None, None
# Dont want to have a class for this, set suffices
visited = set()
queue = deque([(start, [start], set())]) # (current_node, path, edgesGoneToGetHere)
while queue:
currentNode, path, edgesGone = queue.popleft()
if currentNode == goal:
return path, edgesGone
if currentNode not in visited:
logger.info(f"visiting {currentNode}")
visited.add(currentNode)
for neighbor in self.adjacencyList[currentNode]:
edge = (currentNode, neighbor)
# We already went this Edge. Read Part3 as not allowing this to happen
edgeReverse = (neighbor, currentNode)
if neighbor not in visited and (edgesGonePassed is None or edge not in edgesGonePassed) and (edgesGonePassed is None or edgeReverse not in edgesGonePassed):
# Pythonic way of saying neighbour, path no next clear neighbour
# and union of edgesGone with current edge
queue.append((neighbor, path + [neighbor], edgesGone | {edge}))
return None, None
def graphvizify(filePath: str, outputFile: str = 'build/hoehleGraph'):
graph = Digraph()
graph.attr(rankdir='TB')
graph.attr('node', shape='circle', style='filled', fillcolor='lightgray')
graph.attr('edge', arrowsize='0.7')
# Reuse the function to also create our Graph... Waste not want not^^
caveGraph = Graph();
with open(filePath, 'r') as f:
for line in f:
line = line.strip()
delimiter = '<>' if '<>' in line else '>' if '>' in line else None
if delimiter:
node1, node2 = map(str.strip, line.split(delimiter))
node1, node2 = map(lambda x: x.strip('"'), map(str.strip, line.split(delimiter)))
graph.edge(f"\"{node1}\"", f"\"{node2}\"", dir='none' if delimiter == '<>' else None)
caveGraph.addEdge(node1, node2, (delimiter == '<>'));
try:
graph.render(outputFile, view=True)
except Exception as e:
print(f"Could not display graph: {e}\n Trying to save without viewing!")
try:
graph.render(outputFile, view=False)
print(f"Your built map should be available here: {outputFile}.pdf")
except Exception as e:
print(f"Could not save graph file: {e}")
return caveGraph
if __name__ == "__main__":
for filename in [ "data/hoehle.txt", "data/hoehleLarger.txt"]:
caveGraph = graphvizify(filename, 'build/hoehleGraph')
start = "Höhleneingang"
goal = "Schatzkammer"
shortestPath, edgesGoneInitial = caveGraph.breadthFirstSearch(start, goal)
logger.debug(caveGraph.adjacencyList)
logger.debug(edgesGoneInitial)
if shortestPath:
print(f"Shortest path from {start} to {goal} is:")
print(" -> ".join(shortestPath))
else:
print(f"No path found from {start} to {goal}.")
returnpath, _ = caveGraph.breadthFirstSearch(goal, start, edgesGoneInitial)
if returnpath:
print(f"Shortest path from {goal} to {start} is:")
print(" -> ".join(returnpath))
else:
print("No path back Home found. Good Luck")
exit(0)

View File

@ -1,60 +0,0 @@
import logging
logger = logging.getLogger(__name__)
with open('2024/data/input16.data') as f:
# with open('2024/data/input16.example') as f:
# Dont need edges, these are irrelevant to us
content = [list(line.strip()[1:-1]) for line in f.readlines()[1:-1]]
directions = {'N': (-1, 0), 'E': (0, 1), 'S': (1, 0), 'W': (0, -1)}
start = next((row, col, 'E') for row in range(len(content)) for col in range(len(content[0])) if content[row][col] == 'S')
end = next((row, col) for row in range(len(content)) for col in range(len(content[0])) if content[row][col] == 'E')
# Python it up^^ (outer loop goes over each cell in grid and continues with non-walls,
# for each valid cell go over all directions and applies costs dependent on turning)
graph = { (row, col, dirName): {(row+nextdirRow, col+nextdirCol, nextDir): (0 if dirName == nextDir else 1000) + 1
for nextDir, (nextdirRow, nextdirCol) in directions.items()
if 0 <= row+nextdirRow < len(content) and 0 <= col+nextdirCol < len(content[0]) and content[row+nextdirRow][col+nextdirCol] != '#'}
for row in range(len(content)) for col in range(len(content[0])) if content[row][col] != '#' for dirName in directions }
# Algo
def dijsktra(graph, start, end):
import heapq # Priority Queue, Do not use own for shorter Code^^
pq, costs, predecessors = [(0, start)], {node: float('inf') for node in graph}, {node: None for node in graph}
costs[start] = 0
while pq:
cost, node = heapq.heappop(pq)
logger.debug(f"Procesing node {node} with current cost {cost}")
if node[:2] == end[:2]: # Stop when reaching the end position, dont care about direction
path = []
while node:
path.append(node)
node = predecessors[node]
logger.debug(f"Final cost: {cost}")
return cost, path[::-1] # Reverse path to get start-to-end order
if cost > costs[node]: continue
for neighbor, edge_cost in graph[node].items():
if (new_cost := cost + edge_cost) < costs[neighbor]:
costs[neighbor], predecessors[neighbor] = new_cost, node
heapq.heappush(pq, (new_cost, neighbor))
logger.debug(f"Relaxing edge {node} -> {neighbor}, edge cost: {edge_cost}, new cost: {new_cost}")
return float('inf'), [] # No path found
def drawGraph(content, path=None):
# Create copy of grid to overlay graph -> No inPlace Stuff
grid = [row[:] for row in content]
if path:
symbols = {'N': '^', 'E': '>', 'S': 'v', 'W': '<'}
for row, col, direction in path:
grid[row][col] = symbols[direction]
return '\n'.join(''.join(row) for row in grid)
costShortest, shortestPath = dijsktra(graph, start, end)
print("Shortest path cost:", costShortest)
print(drawGraph(content, shortestPath))

View File

@ -1,7 +1,7 @@
from utils.memory_array import MemoryArray
from utils.memory_cell import MemoryCell
from utils.literal import Literal
from utils.constants import MIN_VALUE
from utils.constants import MAX_VALUE
from utils.memory_range import mrange
# Impl of MemoryArray says we cant add our own Datatypes beside Literal and List
@ -28,14 +28,14 @@ class HeapEntry:
return True
if isinstance(other, (int, float)):
return self.getPriority().value > other
return self.getPriority() < other.getPriority()
return self.getPriority() > other.getPriority()
def __gt__(self, other):
if other is None:
return False
if isinstance(other, (int, float)):
return self.getPriority().value < other
return self.getPriority() > other.getPriority()
return self.getPriority() < other.getPriority()
def __eq__(self, other):
return self.getPriority() == other.getPriority()
@ -49,7 +49,7 @@ class PriorityQueue:
# Add uninitialized HeapEntry Values so the Adds/Compares do not fail on emtpy stack.
# Would have to switch to MIN_VALUE if we switch what is a "Higher" Prio
for i in mrange(max_size.value):
self.heap[i].set([HeapEntry(MIN_VALUE, MIN_VALUE)])
self.heap[i].set([HeapEntry(MAX_VALUE, MAX_VALUE)])
self.size = MemoryCell(0)
def parent(self, i: Literal) -> Literal:
@ -89,12 +89,11 @@ class PriorityQueue:
i = self.size
self.heap[i].set([entry])
self.size += Literal(1)
while i > Literal(0) and self.heap[self.parent(i)].value[0] < self.heap[i].value[0]:
self.swap(i, self.parent(i))
i = self.parent(i)
self.size += Literal(1)
def pop(self):
if self.isEmpty():
@ -120,35 +119,6 @@ class PriorityQueue:
def __len__(self):
return self.size
def __str__(self):
entries = []
for i in mrange(self.size.value):
entry = self.heap[i].value[0]
if entry.getItem() != MIN_VALUE:
entries.append(str(entry))
return "[" + ", ".join(entries) + "]"
def testQueueRandom(number: int):
import random
import string
pq = PriorityQueue(Literal(number))
entries = []
for _ in range(number):
value = ''.join(random.choices(string.ascii_uppercase + string.digits, k=3))
priority = random.randint(1, 100)
entry = HeapEntry(value, priority)
entries.append(entry)
pq.insert(entry)
print(pq)
for entry in entries:
print(f"Unprioritized: {entry}")
while not pq.isEmpty():
print(pq.pop())
if __name__ == '__main__':
# Proof of Concept
@ -173,21 +143,16 @@ if __name__ == '__main__':
assert(not pq.isEmpty())
assert(pq.pop() == HeapEntry("A", 1))
assert(pq.isEmpty())
pq.insert(HeapEntry("A", 1))
pq.insert(HeapEntry("C", 3))
pq.insert(HeapEntry("B", 2))
pq.insert(HeapEntry("A", 1))
assert(pq.size == Literal(3))
assert(pq.pop() == HeapEntry("C", 3))
assert(pq.pop() == HeapEntry("B", 2))
assert(pq.pop() == HeapEntry("A", 1))
assert(pq.pop() == HeapEntry("B", 2))
assert(pq.pop() == HeapEntry("C", 3))
pq.insert(HeapEntry("A", 1))
pq.insert(HeapEntry("C", 3))
pq.insert(HeapEntry("B", 2))
pq.insert(HeapEntry(42, 4))
pq.insert(HeapEntry(42, 1))
pq.insert(HeapEntry("C", 2))
print(pq)
while not pq.isEmpty():
print(pq.pop())
testQueueRandom(100)
print(pq.pop())
print(pq.pop())
print(pq.pop())

View File

@ -21,8 +21,6 @@ class Literal:
def __eq__(self, other):
"""Vergleicht den Wert mit einem anderen Wert."""
if other is None:
return False
assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell"
self.compare_count += 1
self.read_count += 1
@ -31,8 +29,6 @@ class Literal:
def __ne__(self, other):
"""Vergleicht den Wert der Speicherzelle mit einem anderen Wert."""
if other is None:
return True
assert isinstance(other, Literal), "Can only compare with Literal or MemoryCell"
self.compare_count += 1
self.read_count += 1

View File

@ -1,7 +1,7 @@
from utils.literal import Literal
from utils.memory_cell import MemoryCell
from utils.memory_manager import MemoryManager
from utils.project_dir import get_path
from pathlib import Path
from random import randint
class MemoryArray:
@ -88,7 +88,9 @@ class MemoryArray:
@staticmethod
def create_array_from_file(filename, limit=None):
"""Erzeugt ein Speicherarray aus einer Datei."""
filename = get_path(filename)
this_dir = Path(__file__).resolve().parent
project_dir = this_dir.parent
filename = project_dir / filename
with open(filename) as f:
lines = f.readlines()
if limit is not None:
@ -100,13 +102,6 @@ class MemoryArray:
a.reset_counters()
return a
def __str__(self):
result = "[ "
for cell in self.cells:
result += str(cell) + ", "
result += "]"
return result
if __name__ == "__main__":
import random
@ -120,7 +115,3 @@ if __name__ == "__main__":
s += cell
print(s)
print(f"Anzahl der Additionen: {MemoryManager.count_adds()}")
a = MemoryArray.create_array_from_file("data/seq0.txt")
print(a)

View File

@ -1,40 +0,0 @@
import heapq
class PriorityQueue:
def __init__(self):
self.heap = []
self.entry_finder = {} # map: item -> [priority, item]
self.REMOVED = '<removed>'
self.counter = 0 # unique sequence count to break ties
def add_or_update(self, item, priority):
if item in self.entry_finder:
self.remove(item)
count = self.counter
entry = [priority, count, item]
self.entry_finder[item] = entry
heapq.heappush(self.heap, entry)
self.counter += 1
def remove(self, item):
entry = self.entry_finder.pop(item)
entry[-1] = self.REMOVED # mark as removed
def pop(self):
while self.heap:
priority, count, item = heapq.heappop(self.heap)
if item != self.REMOVED:
del self.entry_finder[item]
return item, priority
return None
if __name__ == "__main__":
pq = PriorityQueue()
pq.add_or_update('task1', 1)
pq.add_or_update('task2', float('inf'))
pq.add_or_update('task3', float('inf'))
print(pq.pop()) # Should print ('task1', 1)
pq.add_or_update('task2', 0) # Update priority of 'task1'
print(pq.pop()) # Should print ('task2', 0)
print(pq.pop()) # Should print ('task3', 3)

View File

@ -1,13 +0,0 @@
from pathlib import Path
def get_path(filename) -> Path:
this_dir = Path(__file__).resolve().parent
project_dir = this_dir.parent
return project_dir / filename
if __name__ == "__main__":
filename = get_path("data/seq0.txt")
print(filename)
print(filename.resolve())
print(filename.is_file())
print(filename.exists())

View File

@ -5,6 +5,7 @@ from utils.memory_range import mrange
from utils.literal import Literal
def quick_sort_stepwise(z: MemoryArray, l: Literal, r: Literal):
n = z.length()
if l < r:
q = partition(z, l, r)
yield z
@ -76,6 +77,6 @@ def swap(z: MemoryArray, i: int, j: int):
if __name__ == '__main__':
sizes = range(10, 101, 5)
#analyze_complexity(quick_sort, sizes)
analyze_complexity(quick_sort, sizes, True)
sizes = range(10, 101, 10)
analyze_complexity(quick_sort, sizes)
# analyze_complexity(quick_sort, sizes, True)

View File

@ -1,60 +0,0 @@
from utils.memory_array import MemoryArray
from utils.memory_cell import MemoryCell
from utils.memory_manager import MemoryManager
from utils.memory_range import mrange
from utils.literal import Literal
def count_sort(a: MemoryArray, b: MemoryArray, k: int):
c = MemoryArray(Literal(k + 1))
for i in mrange(Literal(k + 1)):
c[i].set(Literal(0))
for j in mrange(a.length()):
c[a[j]].set(c[a[j]].succ())
for i in mrange(Literal(1), Literal(k + 1)):
c[i].set(int(c[i]) + int(c[i.pred()]))
for j in mrange(a.length().pred(), Literal(-1), Literal(-1)):
b[c[a[j]].pred()].set(a[j])
c[a[j]].set(c[a[j]].pred())
def analyze_complexity(sizes, presorted=False):
"""
Analysiert die Komplexität einer Sortierfunktion.
:param sizes: Eine Liste von Eingabegrößen für die Analyse.
"""
for size in sizes:
MemoryManager.purge() # Speicher zurücksetzen
if presorted:
random_array = MemoryArray.create_sorted_array(size, 0, 100)
else:
random_array = MemoryArray.create_random_array(size, 0, 100)
dest_array = MemoryArray(Literal(size))
count_sort(random_array, dest_array, 100)
MemoryManager.save_stats(size)
MemoryManager.plot_stats(["cells", "compares", "writes"])
def swap(z: MemoryArray, i: int, j: int):
tmp = z[Literal(i)].value
z[Literal(i)] = z[Literal(j)]
z[Literal(j)].set(tmp)
if __name__ == '__main__':
# Test the count_sort function
a = MemoryArray([2, 5, 3, 0, 2, 3, 0, 3])
b = MemoryArray(Literal(len(a)))
count_sort(a, b, 5)
sizes = range(10, 101, 10)
analyze_complexity(sizes)
# analyze_complexity(sizes, True)

View File

@ -1 +0,0 @@
from vorlesung.L05_binaere_baeume.bin_tree import BinaryTree

View File

@ -1,26 +0,0 @@
from utils.memory_manager import MemoryManager
from utils.memory_array import MemoryArray
from utils.literal import Literal
from vorlesung.L05_binaere_baeume.avl_tree import AVLTree
def analyze_complexity(sizes):
"""
Analysiert die Komplexität
:param sizes: Eine Liste von Eingabegrößen für die Analyse.
"""
for size in sizes:
MemoryManager.purge() # Speicher zurücksetzen
tree = AVLTree()
random_array = MemoryArray.create_random_array(size, -100, 100)
for i in range(size-1):
tree.insert(int(random_array[Literal(i)]))
MemoryManager.reset()
tree.insert(int(random_array[Literal(size-1)]))
MemoryManager.save_stats(size)
MemoryManager.plot_stats(["cells", "compares"])
if __name__ == "__main__":
sizes = range(1, 1001, 2)
analyze_complexity(sizes)

View File

@ -1,26 +0,0 @@
from utils.memory_manager import MemoryManager
from utils.memory_array import MemoryArray
from utils.literal import Literal
from vorlesung.L05_binaere_baeume.bin_tree import BinaryTree
def analyze_complexity(sizes):
"""
Analysiert die Komplexität
:param sizes: Eine Liste von Eingabegrößen für die Analyse.
"""
for size in sizes:
MemoryManager.purge() # Speicher zurücksetzen
tree = BinaryTree()
random_array = MemoryArray.create_random_array(size, -100, 100)
for i in range(size-1):
tree.insert(int(random_array[Literal(i)]))
MemoryManager.reset()
tree.insert(int(random_array[Literal(size-1)]))
MemoryManager.save_stats(size)
MemoryManager.plot_stats(["cells", "compares"])
if __name__ == "__main__":
sizes = range(1, 1001, 2)
analyze_complexity(sizes)

View File

@ -1,94 +0,0 @@
from utils.memory_array import MemoryArray
from vorlesung.L05_binaere_baeume.avl_tree_node import AVLTreeNode
from vorlesung.L05_binaere_baeume.bin_tree import BinaryTree
import logging
class AVLTree(BinaryTree):
def __init__(self):
super().__init__()
def new_node(self, value):
return AVLTreeNode(value)
def balance(self, node: AVLTreeNode):
node.update_balance()
if node.balance == -2:
if node.left.balance <= 0:
node = node.right_rotate()
else:
node = node.left_right_rotate()
elif node.balance == 2:
if node.right.balance >= 0:
node = node.left_rotate()
else:
node = node.right_left_rotate()
if node.parent:
self.balance(node.parent)
else:
self.root = node
def insert(self, value):
insert_generator = self.insert_stepwise(value)
node, parent = None, None
while True:
try:
node, parent = next(insert_generator)
except StopIteration:
break
return node, parent
def insert_stepwise(self, value):
node, parent = super().insert(value)
yield None, None
node.parent = parent
if parent:
self.balance(parent)
return node, parent
def delete(self, value):
node, parent = super().delete(value)
if node:
node.parent = parent
if parent:
self.balance(parent)
def graph_filename(self):
return "AVLTree"
if __name__ == "__main__":
def print_node(node, indent=0, level=0):
print((indent * 3) * " ", node.value)
tree = AVLTree()
#values = [5, 3, 7, 2, 4, 6, 5, 8]
values = MemoryArray.create_array_from_file("data/seq2.txt")
for value in values:
tree.insert(value)
print("In-order traversal:")
tree.in_order_traversal(print_node)
print("\nLevel-order traversal:")
tree.level_order_traversal(print_node)
print("\nTree structure traversal:")
tree.tree_structure_traversal(print_node)
print("\nGraph traversal:")
tree.graph_traversal()
tree.insert(9)
tree.graph_traversal()
print("\nDeleting 5:")
tree.delete(5)
print("In-order traversal after deletion:")
tree.in_order_traversal(print_node)
print("\nLevel-order traversal after deletion:")
tree.level_order_traversal(print_node)
print("\nTree structure traversal after deletion:")
tree.tree_structure_traversal(print_node)

View File

@ -1,59 +0,0 @@
import random
import pygame
from utils.game import Game
from avl_tree import AVLTree
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
WIDTH = 800
HEIGHT = 400
MARGIN = 20
class AVLTreeGame(Game):
def __init__(self):
super().__init__("AVLTree Game", fps=10, size=(WIDTH, HEIGHT))
random.seed()
self.z = list(range(1, 501))
random.shuffle(self.z)
self.finished = False
self.tree = AVLTree()
self.tree.get_height = lambda node: 0 if node is None else 1 + max(self.tree.get_height(node.left), self.tree.get_height(node.right))
self.height = self.tree.get_height(self.tree.root)
self.generator = None
def update_game(self):
if not self.finished:
if self.generator is None:
self.generator = self.tree.insert_stepwise(self.z.pop())
try:
next(self.generator)
except StopIteration:
self.generator = None
if self.generator is None and len(self.z) == 0:
self.finished = True
self.height = self.tree.get_height(self.tree.root)
return True
def draw_game(self):
self.screen.fill(WHITE)
if self.height > 0:
self.draw_tree(self.tree.root, WIDTH // 2, MARGIN, WIDTH // 4 - MARGIN)
super().draw_game()
def draw_tree(self, node, x, y, x_offset):
y_offset = (HEIGHT - (2 * MARGIN)) / self.height
if node is not None:
pygame.draw.circle(self.screen, BLUE, (x, y), 2)
if node.left is not None:
pygame.draw.line(self.screen, BLACK, (x, y), (x - x_offset, y + y_offset))
self.draw_tree(node.left, x - x_offset, y + y_offset, x_offset // 2)
if node.right is not None:
pygame.draw.line(self.screen, BLACK, (x, y), (x + x_offset, y + y_offset))
self.draw_tree(node.right, x + x_offset, y + y_offset, x_offset // 2)
if __name__ == "__main__":
tree_game = AVLTreeGame()
tree_game.run()

View File

@ -1,61 +0,0 @@
from vorlesung.L05_binaere_baeume.bin_tree_node import BinaryTreeNode
class AVLTreeNode(BinaryTreeNode):
def __init__(self, value):
super().__init__(value)
self.parent = None
self.balance = 0
def __repr__(self):
return f"TreeNode(id={id(self)} value={self.value}, left={self.left}, right={self.right})"
def graphviz_rep(self, row, col, dot):
dot.node(str(id(self)), label=str(self.value), pos=f"{col},{-row}!", xlabel=str(self.balance))
def update_balance(self):
left_height = self.left.height() if self.left else 0
right_height = self.right.height() if self.right else 0
self.balance = right_height - left_height
def right_rotate(self):
new_root = self.left
new_root.parent = self.parent
self.left = new_root.right
if self.left:
self.left.parent = self
new_root.right = self
self.parent = new_root
if new_root.parent:
if new_root.parent.left is self:
new_root.parent.left = new_root
else:
new_root.parent.right = new_root
self.update_balance()
new_root.update_balance()
return new_root
def left_rotate(self):
new_root = self.right
new_root.parent = self.parent
self.right = new_root.left
if self.right:
self.right.parent = self
new_root.left = self
self.parent = new_root
if new_root.parent:
if new_root.parent.left is self:
new_root.parent.left = new_root
else:
new_root.parent.right = new_root
self.update_balance()
new_root.update_balance()
return new_root
def right_left_rotate(self):
self.right = self.right.right_rotate()
return self.left_rotate()
def left_right_rotate(self):
self.left = self.left.left_rotate()
return self.right_rotate()

View File

@ -1,61 +0,0 @@
import random
from utils.memory_array import MemoryArray
from utils.memory_cell import MemoryCell
from utils.memory_manager import MemoryManager
from utils.memory_range import mrange
from utils.literal import Literal
def binary_search(z: MemoryArray, s: MemoryCell, l: Literal = None, r: Literal = None):
"""
Perform a binary search on the sorted array z for the value x.
"""
if l is None:
l = Literal(0)
if r is None:
r = Literal(z.length().pred())
if l > r:
return None
with MemoryCell(l) as m:
m += r
m //= Literal(2)
if s < z[m]:
return binary_search(z, s, l, m.pred())
elif s > z[m]:
return binary_search(z, s, m.succ(), r)
else:
return m
def analyze_complexity(sizes):
"""
Analysiert die Komplexität
:param sizes: Eine Liste von Eingabegrößen für die Analyse.
"""
for size in sizes:
MemoryManager.purge() # Speicher zurücksetzen
random_array = MemoryArray.create_sorted_array(size)
search_value = random.randint(-100, 100)
binary_search(random_array, MemoryCell(search_value))
MemoryManager.save_stats(size)
MemoryManager.plot_stats(["cells", "compares", "adds"])
if __name__ == "__main__":
# Example usage
arr = MemoryArray([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
search_value = MemoryCell(8)
result = binary_search(arr, search_value)
if result is not None:
print(f"Value {search_value} found at index {result}.")
else:
print(f"Value {search_value} not found in the array.")
sizes = range(1, 1001, 2)
analyze_complexity(sizes)

View File

@ -1,206 +0,0 @@
from vorlesung.L05_binaere_baeume.bin_tree_node import BinaryTreeNode
from utils.project_dir import get_path
from datetime import datetime
import graphviz
class BinaryTree:
def __init__(self):
self.root = None
self.size = 0
def new_node(self, value):
return BinaryTreeNode(value)
def insert(self, value):
self.size += 1
value = self.new_node(value)
if self.root is None:
self.root = value
return self.root, None
else:
current = self.root
while True:
if value < current:
if current.left:
current = current.left
else:
current.left = value
return current.left, current
elif value >= current:
if current.right:
current = current.right
else:
current.right = value
return current.right, current
else:
return None, None
def search(self, value):
current = self.root
value = self.new_node(value)
while current:
if value < current:
current = current.left
elif value > current:
current = current.right
else:
return current
return None
def delete(self, value):
# Der Wert wird im Baum gesucht und der erste Treffer gelöscht
# Rückgabe falls der Wert gefunden wird:
# der Knoten, der den zu löschenden Knoten ersetzt und der Elternknoten des gelöschten Knotens
parent = None
current = self.root
value = self.new_node(value)
while current:
if value < current:
parent = current
current = current.left
elif value > current:
parent = current
current = current.right
else:
# Knoten gefunden
break
else:
# Wert nicht gefunden
return None, None
return self.delete_node(current, parent)
def delete_node(self, current, parent):
# Der übergebene Knoten wird
# Rückgabe ist ein Tupel:
# der Knoten, der den zu löschenden Knoten ersetzt und der Elternknoten des gelöschten Knotens
self.size -= 1
# Fall 3: Es gibt zwei Kinder: wir suchen den Nachfolger
if current.left and current.right:
parent = current
successor = current.right
while successor.left:
parent = successor
successor = successor.left
# Wert des Nachfolgers wird in den Knoten geschrieben, der gelöscht werden soll
current.value = successor.value
# Ab jetzt muss successor gelöscht werden; parent ist bereits richtig gesetzt
current = successor
# Ermitteln des einen Kindes (falls es eines gibt), sonst None
# Das eine Kind ist der Ersatz für den Knoten, der gelöscht werden soll
if current.left:
child = current.left
else:
child = current.right
# Falls es keinen Elternknoten gibt, ist der Ersatzknoten die Wurzel
if not parent:
self.root = child
return child, None
elif parent.left is current:
parent.left = child
return child, parent
else:
parent.right = child
return child, parent
def in_order_traversal(self, callback):
def in_order_traversal_recursive(callback, current):
if current is not None:
in_order_traversal_recursive(callback, current.left)
callback(current)
in_order_traversal_recursive(callback, current.right)
in_order_traversal_recursive(callback, self.root)
def level_order_traversal(self, callback):
if self.root is None:
return
queue = [(self.root, 0)]
while queue:
current, level = queue.pop(0)
callback(current, level)
if current.left is not None:
queue.append((current.left, level + 1))
if current.right is not None:
queue.append((current.right, level + 1))
def tree_structure_traversal(self, callback):
def tree_structure_traversal_recursive(callback, current, level):
nonlocal line
if current:
tree_structure_traversal_recursive(callback, current.left, level + 1)
callback(current, level, line)
line += 1
tree_structure_traversal_recursive(callback, current.right, level + 1)
line = 0
tree_structure_traversal_recursive(callback, self.root, 0)
def graph_filename(self):
return "BinaryTree"
def graph_traversal(self):
def define_node(node, level, line):
nonlocal dot
if node is not None:
node.graphviz_rep(level, line, dot)
def graph_traversal_recursive(current):
nonlocal dot
if current is not None:
if current.left:
dot.edge(str(id(current)), str(id(current.left)))
graph_traversal_recursive(current.left)
if current.right:
dot.edge(str(id(current)), str(id(current.right)))
graph_traversal_recursive(current.right)
dot = graphviz.Digraph( name="BinaryTree",
engine="neato",
node_attr={"shape": "circle", "fontname": "Arial"},
format="pdf" )
self.tree_structure_traversal(define_node)
graph_traversal_recursive(self.root)
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"{self.graph_filename()}_{timestamp}.gv"
filename = get_path(filename)
dot.render(filename)
if __name__ == "__main__":
tree = BinaryTree()
values = [5, 3, 7, 2, 4, 6, 5, 8]
for value in values:
tree.insert(value)
def print_node(node, indent=0, line=None):
print((indent * 3) * " ", node.value)
print("In-order traversal:")
tree.in_order_traversal(print_node)
print("\nLevel-order traversal:")
tree.level_order_traversal(print_node)
print("\nTree structure traversal:")
tree.tree_structure_traversal(print_node)
print("\nGraph traversal:")
tree.graph_traversal()
print("\nDeleting 5:")
tree.delete(5)
print("In-order traversal after deletion:")
tree.in_order_traversal(print_node)
print("\nLevel-order traversal after deletion:")
tree.level_order_traversal(print_node)
print("\nTree structure traversal after deletion:")
tree.tree_structure_traversal(print_node)

View File

@ -1,54 +0,0 @@
import random
import pygame
from utils.game import Game
from bin_tree import BinaryTree
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
BLACK = (0, 0, 0)
WIDTH = 800
HEIGHT = 400
MARGIN = 20
class BinTreeGame(Game):
def __init__(self):
super().__init__("BinTree Game", fps=10, size=(WIDTH, HEIGHT))
random.seed()
self.z = list(range(1, 101))
random.shuffle(self.z)
self.finished = False
self.tree = BinaryTree()
self.tree.get_height = lambda node: 0 if node is None else 1 + max(self.tree.get_height(node.left), self.tree.get_height(node.right))
self.height = self.tree.get_height(self.tree.root)
def update_game(self):
if not self.finished:
i = self.z.pop()
self.tree.insert(i)
self.height = self.tree.get_height(self.tree.root)
if len(self.z) == 0:
self.finished = True
return True
def draw_game(self):
self.screen.fill(WHITE)
if self.height > 0:
self.draw_tree(self.tree.root, WIDTH // 2, MARGIN, WIDTH // 4 - MARGIN)
super().draw_game()
def draw_tree(self, node, x, y, x_offset):
y_offset = (HEIGHT - (2 * MARGIN)) / self.height
if node is not None:
pygame.draw.circle(self.screen, BLUE, (x, y), 2)
if node.left is not None:
pygame.draw.line(self.screen, BLACK, (x, y), (x - x_offset, y + y_offset))
self.draw_tree(node.left, x - x_offset, y + y_offset, x_offset // 2)
if node.right is not None:
pygame.draw.line(self.screen, BLACK, (x, y), (x + x_offset, y + y_offset))
self.draw_tree(node.right, x + x_offset, y + y_offset, x_offset // 2)
if __name__ == "__main__":
tree_game = BinTreeGame()
tree_game.run()

View File

@ -1,22 +0,0 @@
from utils.memory_cell import MemoryCell
class BinaryTreeNode(MemoryCell):
def __init__(self, value):
super().__init__(value)
self.left = None
self.right = None
def height(self):
left_height = self.left.height() if self.left else 0
right_height = self.right.height() if self.right else 0
return 1 + max(left_height, right_height)
def __repr__(self):
return f"TreeNode(value={self.value}, left={self.left}, right={self.right})"
def __str__(self):
return str(self.value)
def graphviz_rep(self, row, col, dot):
dot.node(str(id(self)), label=str(self.value), pos=f"{col},{-row}!")

View File

@ -1,58 +0,0 @@
from utils.memory_manager import MemoryManager
from utils.memory_array import MemoryArray
from utils.literal import Literal
from b_tree import BTree
from b_tree_node import BTreeNode
class MemoryManagerBTree(MemoryManager):
"""
Diese Klasse erweitert den MemoryManager, um spezifische Statistiken für B-Bäume zu speichern.
"""
@staticmethod
def count_loads():
return sum([cell.loaded_count for cell in MemoryManager().cells if isinstance(cell, BTreeNode)])
@staticmethod
def count_saves():
return sum([cell.saved_count for cell in MemoryManager().cells if isinstance(cell, BTreeNode)])
@staticmethod
def save_stats(count):
data = { "cells": MemoryManager.count_cells(),
"reads": MemoryManager.count_reads(),
"writes": MemoryManager.count_writes(),
"compares": MemoryManager.count_compares(),
"adds": MemoryManager.count_adds(),
"subs": MemoryManager.count_subs(),
"muls": MemoryManager.count_muls(),
"divs": MemoryManager.count_divs(),
"bitops": MemoryManager.count_bitops(),
"loads": MemoryManagerBTree.count_loads(),
"saves": MemoryManagerBTree.count_saves() }
MemoryManager.stats[count] = data
def analyze_complexity(sizes):
"""
Analysiert die Komplexität
:param sizes: Eine Liste von Eingabegrößen für die Analyse.
"""
for size in sizes:
MemoryManager.purge() # Speicher zurücksetzen
tree = BTree(5)
random_array = MemoryArray.create_random_array(size, -100, 100)
for i in range(size-1):
tree.insert(int(random_array[Literal(i)]))
MemoryManager.reset()
tree.insert(int(random_array[Literal(size-1)]))
MemoryManagerBTree.save_stats(size)
MemoryManager.plot_stats(["cells", "compares", "loads", "saves"])
if __name__ == "__main__":
sizes = range(1, 1001, 2)
analyze_complexity(sizes)

View File

@ -1,120 +0,0 @@
from utils.literal import Literal
from utils.memory_cell import MemoryCell
from utils.memory_array import MemoryArray
from b_tree_node import BTreeNode
class BTree:
def __init__(self, m: int):
self.m = m
self.root = BTreeNode(m)
def search(self, value, start: BTreeNode = None) -> BTreeNode | None:
if not start:
start = self.root
start.load()
i = 0
if not isinstance(value, MemoryCell):
value = MemoryCell(value)
while i < start.n and value > start.value[Literal(i)]:
i += 1
if i < start.n and value == start.value[Literal(i)]:
return start
if start.leaf:
return None
return self.search(value, start.children[i])
def split_child(self, parent: BTreeNode, i: int):
child = parent.children[i]
child.load()
h = BTreeNode(self.m)
h.leaf = child.leaf
h.n = self.m - 1
for j in range(self.m - 1):
h.value[Literal(j)] = child.value[Literal(j + self.m)]
if not h.leaf:
for j in range(self.m):
h.children[j] = child.children[j + self.m]
for j in range(self.m, child.n + 1):
child.children[j] = None
child.n = self.m - 1
child.save()
h.save()
for j in range(parent.n, i, -1):
parent.children[j + 1] = parent.children[j]
parent.value[Literal(j)] = parent.value[Literal(j - 1)]
parent.children[i + 1] = h
parent.value[Literal(i)] = child.value[Literal(self.m - 1)]
parent.n += 1
parent.save()
def insert(self, value):
if not isinstance(value, MemoryCell):
value = MemoryCell(value)
r = self.root
if r.n == 2 * self.m - 1:
h = BTreeNode(self.m)
self.root = h
h.leaf = False
h.n = 0
h.children[0] = r
self.split_child(h, 0)
self.insert_in_node(h, value)
else:
self.insert_in_node(r, value)
def insert_in_node(self, start: BTreeNode, value):
start.load()
i = start.n
if start.leaf:
while i >= 1 and value < start.value[Literal(i-1)]:
start.value[Literal(i)] = start.value[Literal(i-1)]
i -= 1
start.value[Literal(i)].set(value)
start.n += 1
start.save()
else:
j = 0
while j < start.n and value > start.value[Literal(j)]:
j += 1
if start.children[j].n == 2 * self.m - 1:
self.split_child(start, j)
if value > start.value[Literal(j)]:
j += 1
self.insert_in_node(start.children[j], value)
def traversal(self, callback):
def traversal_recursive(node, callback):
i = 0
while i < node.n:
if not node.leaf:
traversal_recursive(node.children[i], callback)
callback(node.value[Literal(i)])
i += 1
if not node.leaf:
traversal_recursive(node.children[i], callback)
traversal_recursive(self.root, callback)
def walk(self):
def print_key(key):
print(key, end=" ")
self.traversal(print_key)
def height(self, start: BTreeNode = None):
if not start:
start = self.root
if start.leaf:
return 0
return 1 + self.height(start.children[0])
if __name__ == "__main__":
a = MemoryArray.create_array_from_file("data/seq3.txt")
tree = BTree(3)
for cell in a:
tree.insert(cell)
print(f"Height: {tree.height()}")
tree.walk()
s = tree.search(0)
print(f"\nKnoten mit 0: {str(s)}")

View File

@ -1,29 +0,0 @@
from utils.literal import Literal
from utils.memory_cell import MemoryCell
from utils.memory_array import MemoryArray
class BTreeNode(MemoryCell):
def __init__(self, m: int):
super().__init__()
self.m = m
self.n = 0
self.leaf = True
self.value = MemoryArray(Literal(2 * m - 1))
self.children = [None] * (2 * m)
self.loaded_count = 0
self.saved_count = 0
def reset_counters(self):
super().reset_counters()
self.loaded_count = 0
self.saved_count = 0
def load(self):
self.loaded_count += 1
def save(self):
self.saved_count += 1
def __str__(self):
return "(" + " ".join([str(self.value[Literal(i)]) for i in range(self.n)]) + ")"

View File

@ -1,60 +0,0 @@
import math
import random
from utils.literal import Literal
from utils.memory_cell import MemoryCell
from utils.memory_array import MemoryArray
from utils.memory_manager import MemoryManager
from vorlesung.L07_hashtable.hashtable import HashTableOpenAddressing
#Goldener Schnitt
a = Literal((math.sqrt(5) - 1) / 2)
# Hashfunktion nach multiplikativer Methode
def h(x: MemoryCell, m: Literal) -> Literal:
with MemoryCell(int(x * a)) as integer_part, MemoryCell(x * a) as full_product:
with MemoryCell(full_product - integer_part) as fractional_part:
return Literal(abs(int(fractional_part * m)))
# Quadratische Sondierung
def f(x: MemoryCell, i: Literal, m: Literal) -> Literal:
c1 = 1
c2 = 5
with MemoryCell(h(x, m)) as initial_hash, MemoryCell(c2 * int(i) * int(i)) as quadratic_offset:
with MemoryCell(initial_hash + quadratic_offset) as probe_position:
probe_position += Literal(c1 * int(i)) # Linear component
return probe_position % m
# Symmetrische quadratische Sondierung
def fs(x: MemoryCell, i: Literal, m: Literal) -> Literal:
with MemoryCell(h(x, m)) as base_hash, MemoryCell(int(i) * int(i)) as square:
if int(i) % 2 == 0: # gerades i: Vorwärtssondierung
with MemoryCell(base_hash + square) as position:
return position % m
else: # ungerades i: Rückwärtssondierung
with MemoryCell(base_hash - square) as position:
return position % m
def analyze_complexity(sizes):
"""
Analysiert die Komplexität
:param sizes: Eine Liste von Eingabegrößen für die Analyse.
"""
for size in sizes:
MemoryManager.purge() # Speicher zurücksetzen
ht = HashTableOpenAddressing(size, f)
random_array = MemoryArray.create_random_array(size, -100, 100)
for cell in random_array:
ht.insert(cell)
MemoryManager.reset()
cell = random.choice(random_array.cells)
ht.search(cell)
MemoryManager.save_stats(size)
MemoryManager.plot_stats(["cells", "compares"])
if __name__ == "__main__":
sizes = range(1, 1001, 10)
analyze_complexity(sizes)

View File

@ -1,76 +0,0 @@
from collections.abc import Callable
from utils.literal import Literal
from utils.memory_array import MemoryArray
from utils.memory_cell import MemoryCell
from utils.memory_range import mrange
UNUSED_MARK = "UNUSED"
DELETED_MARK = "DELETED"
class HashTableOpenAddressing:
def __init__(self, m: Literal, f: Callable[[MemoryCell, Literal, Literal], Literal]):
if not isinstance(m, Literal):
m = Literal(m)
self.m = m
self.f = f
self.table = MemoryArray(m)
for i in mrange(m):
self.table[i].value = UNUSED_MARK
def insert(self, x: MemoryCell):
with MemoryCell(0) as i:
while i < self.m:
j = self.f(x, i, self.m)
if self.is_free(j):
self.table[j].set(x)
return True
i.set(i.succ())
return False
def search(self, x: MemoryCell):
with MemoryCell(0) as i:
while i < self.m:
j = self.f(x, i, self.m)
if self.is_unused(j):
return False
if self.table[j] == x:
return True
i.set(i.succ())
return False
def delete(self, x: MemoryCell):
with MemoryCell(0) as i:
while i < self.m:
j = self.f(x, i, self.m)
if self.is_unused(j):
return False
if self.table[j] == x:
self.table[j].value = DELETED_MARK
return True
i.set(i.succ())
return False
def __str__(self):
return str(self.table)
def alpha(self):
with MemoryCell(0) as i:
used = 0
while i < self.m:
used += 0 if self.is_free(i) else 1
i.set(i.succ())
return used / int(self.m)
def is_unused(self, i: Literal):
if self.table[i].value == UNUSED_MARK:
return True
return False
def is_deleted(self, i: Literal):
if self.table[i].value == DELETED_MARK:
return True
return False
def is_free(self, i: Literal):
return self.is_unused(i) or self.is_deleted(i)

View File

@ -1,45 +0,0 @@
from vorlesung.L08_graphen.graph import Graph, AdjacencyMatrixGraph
from utils.project_dir import get_path
graph = AdjacencyMatrixGraph()
start = ""
end = ""
def read_file(filename: str = "data/aoc2212.txt"):
"""Read a file and return the content as a string."""
def adjust_char(char):
"""Adjust character for comparison."""
if char == 'S':
return 'a'
elif char == 'E':
return 'z'
return char
global start, end
with open(get_path(filename), "r") as file:
quest = file.read().strip().splitlines()
for row, line in enumerate(quest):
for col, char in enumerate(line):
label = f"{row},{col}"
graph.insert_vertex(label)
if char == "S":
start = label
if char == "E":
end = label
for row, line in enumerate(quest):
for col, char in enumerate(line):
for neighbor in [(row - 1, col), (row, col - 1), (row + 1, col), (row, col + 1)]:
if 0 <= neighbor[0] < len(quest) and 0 <= neighbor[1] < len(line):
if ord(adjust_char(quest[neighbor[0]][neighbor[1]])) <= ord(adjust_char(char)) + 1:
label1 = f"{row},{col}"
label2 = f"{neighbor[0]},{neighbor[1]}"
graph.connect(label1, label2)
# Lösung des Adventskalenders 2022, Tag 12
read_file("data/aoc2212test.txt")
graph.graph()
distance_map, predecessor_map = graph.bfs(start)
print(distance_map[graph.get_vertex(end)])
print(graph.path(end, predecessor_map))

View File

@ -1,366 +0,0 @@
from collections import deque
from typing import List
from enum import Enum
import graphviz
import math
import heapq
from datetime import datetime
from utils.project_dir import get_path
from utils.priority_queue import PriorityQueue
from vorlesung.L09_mst.disjoint import DisjointValue
class NodeColor(Enum):
"""Enumeration for node colors in a graph traversal."""
WHITE = 1 # WHITE: not visited
GRAY = 2 # GRAY: visited but not all neighbors visited
BLACK = 3 # BLACK: visited and all neighbors visited
class Vertex:
"""A vertex in a graph."""
def __init__(self, value):
self.value = value
def __str__(self):
return str(self.value)
def __repr__(self):
return f"Vertex({self.value})"
class Graph:
"""A graph."""
def insert_vertex(self, name: str):
raise NotImplementedError("Please implement this method in subclass")
def connect(self, name1: str, name2: str, weight: float = 1):
raise NotImplementedError("Please implement this method in subclass")
def all_vertices(self) -> List[Vertex]:
raise NotImplementedError("Please implement this method in subclass")
def get_vertex(self, name: str) -> Vertex:
raise NotImplementedError("Please implement this method in subclass")
def get_adjacent_vertices(self, name: str) -> List[Vertex]:
raise NotImplementedError("Please implement this method in subclass")
def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]:
raise NotImplementedError("Please implement this method in subclass")
def all_edges(self) -> List[tuple[str, str, float]]:
raise NotImplementedError("Please implement this method in subclass")
def bfs(self, start_name: str):
"""
Perform a breadth-first search starting at the given vertex.
:param start_name: the name of the vertex to start at
:return: a tuple of two dictionaries, the first mapping vertices to distances from the start vertex,
the second mapping vertices to their predecessors in the traversal tree
"""
color_map = {} # maps vertices to their color
distance_map = {} # maps vertices to their distance from the start vertex
predecessor_map = {} # maps vertices to their predecessor in the traversal tree
# Initialize the maps
for vertex in self.all_vertices():
color_map[vertex] = NodeColor.WHITE
distance_map[vertex] = None
predecessor_map[vertex] = None
# Start at the given vertex
start_node = self.get_vertex(start_name)
color_map[start_node] = NodeColor.GRAY
distance_map[start_node] = 0
# Initialize the queue with the start vertex
queue = deque()
queue.append(start_node)
# Process the queue
while len(queue) > 0:
vertex = queue.popleft()
for dest in self.get_adjacent_vertices(vertex.value):
if color_map[dest] == NodeColor.WHITE:
color_map[dest] = NodeColor.GRAY
distance_map[dest] = distance_map[vertex] + 1
predecessor_map[dest] = vertex
queue.append(dest)
color_map[vertex] = NodeColor.BLACK
# Return the distance and predecessor maps
return distance_map, predecessor_map
def dfs(self):
"""
Perform a depth-first search starting at the first vertex.
:return: a tuple of two dictionaries, the first mapping vertices to distances from the start vertex,
the second mapping vertices to their predecessors in the traversal tree
"""
color_map : dict[Vertex, NodeColor]= {}
enter_map : dict[Vertex, int] = {}
leave_map : dict[Vertex, int] = {}
predecessor_map : dict[Vertex, Vertex | None] = {}
white_vertices = set(self.all_vertices())
time_counter = 0
def dfs_visit(vertex):
nonlocal time_counter
color_map[vertex] = NodeColor.GRAY
white_vertices.remove(vertex)
time_counter += 1
enter_map[vertex] = time_counter
for dest in self.get_adjacent_vertices(vertex.value):
if color_map[dest] == NodeColor.WHITE:
predecessor_map[dest] = vertex
dfs_visit(dest)
color_map[vertex] = NodeColor.BLACK
time_counter += 1
leave_map[vertex] = time_counter
# Initialize the maps
for vertex in self.all_vertices():
color_map[vertex] = NodeColor.WHITE
predecessor_map[vertex] = None
while white_vertices:
v = white_vertices.pop()
dfs_visit(v)
return enter_map, leave_map, predecessor_map
def path(self, destination, map):
"""
Compute the path from the start vertex to the given destination vertex.
The map parameter is the predecessor map
"""
path = []
destination_node = self.get_vertex(destination)
while destination_node is not None:
path.insert(0, destination_node.value)
destination_node = map[destination_node]
return path
def graph(self, filename: str = "Graph"):
dot = graphviz.Digraph( name=filename,
node_attr={"fontname": "Arial"},
format="pdf" )
for vertex in self.all_vertices():
dot.node(str(id(vertex)), label=str(vertex.value))
for edge in self.all_edges():
dot.edge(str(id(self.get_vertex(edge[0]))), str(id(self.get_vertex(edge[1]))), label=str(edge[2]))
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"{filename}_{timestamp}.gv"
filename = get_path(filename)
dot.render(filename)
def dijkstra(self, start_name: str) -> tuple[dict[Vertex, float], dict[Vertex, Vertex | None]]:
"""
Führt den Dijkstra-Algorithmus für kürzeste Pfade durch, implementiert mit Knotenfarben.
Args:
start_name: Name des Startknotens
Returns:
Ein Tupel aus zwei Dictionaries:
- distance_map: Abbildung von Knoten auf ihre kürzeste Distanz vom Startknoten
- predecessor_map: Abbildung von Knoten auf ihre Vorgänger im kürzesten Pfad
"""
def relax(vertex, dest, weight):
"""
Entspannt die Kante zwischen vertex und dest.
Aktualisiert die Distanz und den Vorgänger, wenn ein kürzerer Pfad gefunden wird.
"""
if distance_map[vertex] + weight < distance_map[dest]:
distance_map[dest] = distance_map[vertex] + weight
predecessor_map[dest] = vertex
queue.add_or_update(dest, distance_map[dest])
# Initialisierung der Maps
distance_map = {} # Speichert kürzeste Distanzen
predecessor_map = {} # Speichert Vorgänger
# Initialisiere alle Knoten
queue = PriorityQueue()
for vertex in self.all_vertices():
distance_map[vertex] = float('inf') # Initiale Distanz unendlich
predecessor_map[vertex] = None # Initialer Vorgänger None
queue.add_or_update(vertex, distance_map[vertex]) # Füge Knoten zur Prioritätswarteschlange hinzu
# Setze Startknoten
start_node = self.get_vertex(start_name)
distance_map[start_node] = 0
queue.add_or_update(start_node, distance_map[start_node])
while True:
entry = queue.pop()
if entry is None:
break
vertex = entry[0]
for dest, weight in self.get_adjacent_vertices_with_weight(vertex.value):
relax(vertex, dest, weight)
return distance_map, predecessor_map
def mst_prim(self, start_name: str = None):
""" Compute the minimum spanning tree of the graph using Prim's algorithm. """
distance_map = {} # maps vertices to their current distance from the spanning tree
parent_map = {} # maps vertices to their predecessor in the spanning tree
Vertex.__lt__ = lambda self, other: distance_map[self] < distance_map[other]
queue = []
if start_name is None:
start_name = self.all_vertices()[0].value
# Initialize the maps
for vertex in self.all_vertices():
distance_map[vertex] = 0 if vertex.value == start_name else math.inf
parent_map[vertex] = None
queue.append(vertex)
heapq.heapify(queue) # Convert the list into a heap
# Process the queue
cost = 0 # The cost of the minimum spanning tree
while len(queue) > 0:
vertex = heapq.heappop(queue)
cost += distance_map[vertex] # Add the cost of the edge to the minimum spanning tree
for (dest, w) in self.get_adjacent_vertices_with_weight(vertex.value):
if dest in queue and distance_map[dest] > w:
# Update the distance and parent maps
queue.remove(dest)
distance_map[dest] = w
parent_map[dest] = vertex
queue.append(dest) # Add the vertex back to the queue
heapq.heapify(queue) # Re-heapify the queue
# Return the distance and predecessor maps
return parent_map, cost
def mst_kruskal(self, start_name: str = None):
""" Compute the minimum spanning tree of the graph using Kruskal's algorithm. """
cost = 0
result = []
edges = self.all_edges()
# Create a disjoint set for each vertex
vertex_map = {v.value: DisjointValue(v) for v in self.all_vertices()}
# Sort the edges by weight
edges.sort(key=lambda edge: edge[2])
# Process the edges
for edge in edges:
start_name, end_name, weight = edge
# Check if the edge creates a cycle
if not vertex_map[start_name].same_set(vertex_map[end_name]):
result.append(edge)
vertex_map[start_name].union(vertex_map[end_name])
cost += weight
return result, cost
class AdjacencyListGraph(Graph):
"""A graph implemented as an adjacency list."""
def __init__(self):
self.adjacency_map = {} # maps vertex names to lists of adjacent vertices
self.vertex_map = {} # maps vertex names to vertices
def insert_vertex(self, name: str):
if name not in self.vertex_map:
self.vertex_map[name] = Vertex(name)
if name not in self.adjacency_map:
self.adjacency_map[name] = []
def connect(self, name1: str, name2: str, weight: float = 1):
adjacency_list = self.adjacency_map[name1]
dest = self.vertex_map[name2]
adjacency_list.append((dest, weight))
def all_vertices(self) -> List[Vertex]:
return list(self.vertex_map.values())
def get_vertex(self, name: str) -> Vertex:
return self.vertex_map[name]
def get_adjacent_vertices(self, name: str) -> List[Vertex]:
return list(map(lambda x: x[0], self.adjacency_map[name]))
def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]:
return self.adjacency_map[name]
def all_edges(self) -> List[tuple[str, str, float]]:
result = []
for name in self.adjacency_map:
for (dest, weight) in self.adjacency_map[name]:
result.append((name, dest.value, weight))
return result
class AdjacencyMatrixGraph(Graph):
"""A graph implemented as an adjacency matrix."""
def __init__(self):
self.index_map = {} # maps vertex names to indices
self.vertex_list = [] # list of vertices
self.adjacency_matrix = [] # adjacency matrix
def insert_vertex(self, name: str):
if name not in self.index_map:
self.index_map[name] = len(self.vertex_list)
self.vertex_list.append(Vertex(name))
for row in self.adjacency_matrix: # add a new column to each row
row.append(None)
self.adjacency_matrix.append([None] * len(self.vertex_list)) # add a new row
def connect(self, name1: str, name2: str, weight: float = 1):
index1 = self.index_map[name1]
index2 = self.index_map[name2]
self.adjacency_matrix[index1][index2] = weight
def all_vertices(self) -> List[Vertex]:
return self.vertex_list
def get_vertex(self, name: str) -> Vertex:
index = self.index_map[name]
return self.vertex_list[index]
def get_adjacent_vertices(self, name: str) -> List[Vertex]:
index = self.index_map[name]
result = []
for i in range(len(self.vertex_list)):
if self.adjacency_matrix[index][i] is not None:
name = self.vertex_list[i].value
result.append(self.get_vertex(name))
return result
def get_adjacent_vertices_with_weight(self, name: str) -> List[tuple[Vertex, float]]:
index = self.index_map[name]
result = []
for i in range(len(self.vertex_list)):
if self.adjacency_matrix[index][i] is not None:
name = self.vertex_list[i].value
result.append((self.get_vertex(name), self.adjacency_matrix[index][i]))
return result
def all_edges(self) -> List[tuple[str, str, float]]:
result = []
for i in range(len(self.vertex_list)):
for j in range(len(self.vertex_list)):
if self.adjacency_matrix[i][j] is not None:
result.append((self.vertex_list[i].value, self.vertex_list[j].value, self.adjacency_matrix[i][j]))
return result

View File

@ -1,18 +0,0 @@
class DisjointValue():
def __init__(self, value):
self.value = value
self.parent = None
def canonical(self):
if self.parent:
return self.parent.canonical()
return self
def same_set(self, other):
return self.canonical() == other.canonical()
def union(self, other):
self.canonical().parent = other.canonical()

View File