Code files

main
Gijs 3 years ago
parent d800575095
commit 5840d75449

@ -1,2 +1,21 @@
# tree-sort
Repository for the tree sort algorithm workshop.
You'll find the workshop material in the workshop folder.
## workshop/treesort.py
Implementation of the binary search tree. When the script is
```
python workshop/treesort.py
```
## workshop/text-tree.py
Reads a text (`workshop/text-to-sort.txt`)and generates a visual tree:
```
python/text-tree.py
```

@ -0,0 +1,20 @@
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

@ -0,0 +1 @@
"the quality of light by which we scrutinize our lives has direct bearing upon the product which we live, and upon the changes which we hope to bring about through those lives. It is within this light that we form those ideas by which we pursue our magic and make it realized. This is poetry as illumination, for it is through poetry that we give name to those ideas which are - until the poem - nameless and formless, about to be birthed, but already felt. That distillation of experience from which true poetry springs births thought as dream births concept, as feeling births idea, as knowledge births (precedes) understanding."

@ -0,0 +1,48 @@
from treesort import TreeNode
from visualizer import visualize
from random import shuffle
import os.path
basepath = os.path.dirname(os.path.abspath(__file__))
# Alternative sorting function that has a comparator
def insert (root, value, key = lambda value: value):
if not root:
root = TreeNode()
root.value = value
else:
if value == root.value:
root.value = value
else:
if key(value) < key(root.value):
root.left = insert(root.left, value, key)
else:
root.right = insert(root.right, value, key)
return root
# Alternative make tree that allows for a callback
# which returns the sorting value.
# By default the sort value is the same as the value
def make_tree (values, key = lambda word: word):
tree = None
for value in values:
tree = insert(tree, value, key)
return tree
def clean (word):
return word.lower().strip(' .,!?-"()[]‘’“”')
def not_empty (word):
return (word)
if __name__ == '__main__':
with open(os.path.join(basepath, 'text-to-sort.txt'), 'r') as h:
text = h.read()
words = text.split(' ')
cleaned_words = list(filter(not_empty, map(clean, words)))
shuffle(cleaned_words)
visualize(make_tree(cleaned_words), 'text-tree-random')

@ -0,0 +1,85 @@
from random import randint
# Description of a node
class TreeNode (object):
def __init__ (self, value = None):
self.value = value
self.left = None
self.right = None
"""
This function defines a root for the tree and initiates
the process of looping through the values and inserting
them into the tree.
"""
def make_tree (values):
tree = None
for value in values:
tree = insert(tree, value)
return tree
"""
Adds a node to the tree
"""
def insert (root, value, key = lambda value: value):
# Test whether there is a node at the current location
if not root:
# If not, insert the node here
root = TreeNode()
root.value = value
else:
# There is a node, compare value to be inserted
# and the value of the node to decide whether the
# node should be attached to the left or the right
if key(value) < key(root.value):
root.left = insert(root.left, value, key)
else:
root.right = insert(root.right, value, key)
return root
"""
Measures the depth of a (sub)tree
"""
def measure_tree (node):
if node:
# If there is a node, measure the depth
# of the left and right node
depth_left = measure_tree(node.left)
depth_right = measure_tree(node.right)
# Return the answer with the highest value
# and add one
return max(depth_left, depth_right) + 1
else:
# There isn't a node, answer with the value 0
return 0
def traverse_tree (node):
# Test whether there is a node
if node:
# If there is a node, ask its left node to traverse
tree_left = traverse_tree(node.left)
# and ask the same for its right node
tree_right = traverse_tree(node.right)
# Then combine into a new list:
# the list answered by the left node
# with the value of the node itself
# And the list answered by the right node
#
# Give this new list as an answer to the root node
return tree_left + [ node.value ] + tree_right
else:
# There is no node, return an empty list
return []
if __name__ == '__main__':
values = [randint(0, 100) for _ in range(15)]
tree = make_tree(values)
print(values, tree.value, tree.left.value if tree.left else None, tree.right.value if tree.right else None, measure_tree(tree), traverse_tree(tree))

@ -0,0 +1,38 @@
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