Updated README, simplified initial implementation of treesort simplified file structure.

main
Gijs 3 years ago
parent 7254cf4e55
commit 80d0d02690

@ -1,10 +1,55 @@
# tree-sort # Tree sort
Repository for the tree sort algorithm workshop. Repository for the tree sort algorithm workshop.
You'll find the workshop material in the workshop folder. You'll find the workshop material in the `workshop` folder.
## workshop/treesort.py ## Recipes
Recipes used during the workshop to execute the tree sort algorithm manually (with a group of people).
### To insert a node within a tree
*This recipe inserts a new node into an (empty) tree. It is assumed there is a place defined where the tree will be started (rooting point?). When the recipe is executed the **current position** is considered to be rooting point.*
1. Look at your *current position*, if it's empty (there is no node) this will be your place: you are inserted in the tree, and the recipe is finished. If there is a node continue with step two.
2. Ask the node in the *current position* for its value.
3. Compare the answer of the node to your own value. Is your value smaller than theirs? Then follow the left arm of the node, and take that as the new *current position* and move back to step one. Otherwise continue with step four.
4. Is your own value the same as or bigger than the answer the node gave? Then follow the right arm of the node, and take that as your new *current position* and go back to step one.
### To measure the depth of a tree
*This recipe discovers the depth of the deepest branch in the (sub)tree. It is initiated by asking the root or any other node to measure its depth.*
1. Ask the node attached to your left arm for its depth, or take zero if you have none.
2. Ask the node attached to your right arm for its depth, or take zero if you have none.
3. Pick the greater one out of the answers you collected in step one and two, and add 1 (increment by one).
4. Answer the number you calculated in step 3 to the node which asked you to measure your depth.
### To traverse the tree in order:
*This recipe transforms the (sub)tree into an orderd row (or list)*. It is initiated by asking the root or any other node to traverse.
1. If you have a left node: ask it to traverse. Once it has finished traversing ask the resulting row (list) to stand to the *left* of you. It is important the row maintains it order.
2. If you have a right node: ask it to traverse. Once it has finished traversing ask the resulting row (list) to stand to the *right* of you. It is important the row maintains it order.
3. By combining the row on the left, yourself, and the row to your right a new row has formed. Tell the node who asked you to traverse that you're ready.
## Code implementations
In the folder `workshop/code` a simple implementation of the tree sort algorithm can be found.
### workshop/code/treesort.py
Implementation of the binary search tree. When the script is Implementation of the binary search tree. When the script is
@ -12,7 +57,15 @@ Implementation of the binary search tree. When the script is
python workshop/treesort.py python workshop/treesort.py
``` ```
## workshop/text-tree.py ### workshop/code/tree-visualizer.py
Visualizes a tree using graphviz
```
python/tree_visualizer.py
```
### workshop/code/text-tree.py
Reads a text (`workshop/text-to-sort.txt`) and generates a visual tree: Reads a text (`workshop/text-to-sort.txt`) and generates a visual tree:

@ -1,20 +0,0 @@
from string import ascii_uppercase
# Returns a function to generate node names with given prefix
def make_name_generator (prefix = '', length = 1):
wheels = [{ 'position': None, 'max': len(ascii_uppercase), 'values': list(ascii_uppercase)} for _ in range(length)]
def name_generator ():
for wheel in wheels:
if wheel['position'] is None:
wheel['position'] = 0
else:
wheel['position'] += 1
if wheel['position'] < wheel['max']:
break
else:
wheel['position'] = 0
return prefix + ''.join(reversed([wheel['values'][wheel['position']] for wheel in wheels]))
return name_generator

@ -1,5 +1,5 @@
from treesort import TreeNode from treesort import TreeNode
from visualizer import visualize from tree_visualizer import visualize
from random import shuffle from random import shuffle
import os.path import os.path

@ -0,0 +1,56 @@
from string import ascii_uppercase
from graphviz import Digraph, Graph
# Returns a function to generate node names with an optional prefix
def make_name_generator (length = 1, prefix = ''):
wheels = [{ 'position': None, 'max': len(ascii_uppercase), 'values': list(ascii_uppercase)} for _ in range(length)]
def name_generator ():
for wheel in wheels:
if wheel['position'] is None:
wheel['position'] = 0
else:
wheel['position'] += 1
if wheel['position'] < wheel['max']:
break
else:
wheel['position'] = 0
return prefix + ''.join(reversed([wheel['values'][wheel['position']] for wheel in wheels]))
return name_generator
def visualize (tree, graphname):
generate_node_name = make_name_generator(length=3)
def visualize_node (graph, node, previous_node_name = None, tailport = None):
if node:
node_name = generate_node_name()
graph.node(node_name, label=str(node.value))
if previous_node_name:
graph.edge(previous_node_name, node_name, tailport=tailport, headport='s')
visualize_node(graph, node.left, node_name, 'nw')
# Hack to have a more beautiful layout
visualize_node(graph, None, node_name, 'n')
visualize_node(graph, node.right, node_name, 'ne')
else:
node_name = generate_node_name()
graph.node(node_name, label=node_name, style='invis')
graph.edge(previous_node_name, node_name, style='invis', tailport=tailport, headport='s')
graph = Graph(name=graphname, format='svg', engine='dot')
graph.attr('graph', splines='line', rankdir='BT')
visualize_node(graph, tree)
graph.render(graphname)
if __name__ == '__main__':
from treesort import make_tree
from random import randint
values = [randint(0, 250) for _ in range(15)]
tree = make_tree(values)
visualize(tree, 'tree')

@ -23,7 +23,7 @@ def make_tree (values):
""" """
Adds a node to the tree Adds a node to the tree
""" """
def insert (root, value, key = lambda value: value): def insert (root, value):
# Test whether there is a node at the current location # Test whether there is a node at the current location
if not root: if not root:
# If not, insert the node here # If not, insert the node here
@ -34,10 +34,10 @@ def insert (root, value, key = lambda value: value):
# There is a node, compare value to be inserted # There is a node, compare value to be inserted
# and the value of the node to decide whether the # and the value of the node to decide whether the
# node should be attached to the left or the right # node should be attached to the left or the right
if key(value) < key(root.value): if value < root.value:
root.left = insert(root.left, value, key) root.left = insert(root.left, value)
else: else:
root.right = insert(root.right, value, key) root.right = insert(root.right, value)
return root return root
""" """

@ -1,38 +0,0 @@
from graph_utils import make_name_generator
from graphviz import Digraph, Graph
generate_node_name = make_name_generator(length=3)
def visualize_node (graph, node, previous_node_name = None, tailport = None):
if node:
node_name = generate_node_name()
graph.node(node_name, label=str(node.value))
if previous_node_name:
graph.edge(previous_node_name, node_name, tailport=tailport, headport='s')
visualize_node(graph, node.left, node_name, 'nw')
# Hack to have a more beautiful layout
visualize_node(graph, None, node_name, 'n')
visualize_node(graph, node.right, node_name, 'ne')
else:
node_name = generate_node_name()
graph.node(node_name, label=node_name, style='invis')
graph.edge(previous_node_name, node_name, style='invis', tailport=tailport, headport='s')
def visualize (tree, graphname):
graph = Graph(name=graphname, format='svg', engine='dot')
graph.attr('graph', splines='line', rankdir='BT')
visualize_node (graph, tree)
graph.render(graphname)
if __name__ == '__main__':
from treesort import make_tree
from random import randint
values = [randint(0, 250) for _ in range(15)]
tree = make_tree(values)
visualize(tree, 'tree')
Loading…
Cancel
Save