Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
25a38e0
Update .travis.yml
julienawilson Jan 18, 2017
97e30fc
Update README.md
julienawilson Jan 18, 2017
c8b6b90
added new methods to README and module doctstrings
rveeblefetzer Jan 18, 2017
f7e5913
Merge branch 'bst' of https://github.com/julienawilson/data-structure…
rveeblefetzer Jan 18, 2017
cb54d06
adding delete method
rveeblefetzer Jan 18, 2017
18d7877
added 1-child node instances for delete
rveeblefetzer Jan 18, 2017
4ba611a
delete for node with two childs
julienawilson Jan 18, 2017
cf9a522
added the easy tests for delete
rveeblefetzer Jan 18, 2017
a65f8c6
Merge branch 'bst' of https://github.com/julienawilson/data-structure…
rveeblefetzer Jan 18, 2017
1505ae8
fix in the delete method
julienawilson Jan 18, 2017
136cd50
delete fix
julienawilson Jan 19, 2017
2214ff2
fix in delete, more tests
julienawilson Jan 19, 2017
dba1e85
balance fix
julienawilson Jan 19, 2017
621f7ff
added tests for delete to check two-way connections of deleted; added…
rveeblefetzer Jan 19, 2017
046afe0
cleanup for merge
rveeblefetzer Jan 19, 2017
95ec636
deleted corpse code
rveeblefetzer Jan 19, 2017
cc7ad6c
changed balance method so it can take non-root nodes as argument
rveeblefetzer Jan 19, 2017
5e0c421
added autobalanc helper functions to rotate left/right
rveeblefetzer Jan 19, 2017
c63dc6d
tests for rotation
julienawilson Jan 19, 2017
98ec9d1
bug in left right rotation
julienawilson Jan 24, 2017
b26a465
true/false switch for autobalancing tree
julienawilson Jan 24, 2017
99a354c
fixed the rotations bug. small operator error.
julienawilson Jan 24, 2017
61c5e7d
adding to docstrings
rveeblefetzer Jan 24, 2017
276306e
Merge branch 'bst' of https://github.com/julienawilson/data-structure…
rveeblefetzer Jan 24, 2017
343328a
Merge branch 'bst-rotation' of https://github.com/julienawilson/data-…
rveeblefetzer Jan 24, 2017
2f8af43
added docstrings, made autobalance, rebalance and rotations into hidd…
rveeblefetzer Jan 24, 2017
04d8649
adding initial files
rveeblefetzer Jan 25, 2017
ae697bd
hash table
julienawilson Jan 25, 2017
41bcb9e
Merge branch 'hash-table' of https://github.com/julienawilson/data-st…
rveeblefetzer Jan 25, 2017
14197b9
added pseudocode-ish addititve hash
rveeblefetzer Jan 25, 2017
366131f
add hash func written
julienawilson Jan 25, 2017
577725b
added blank test file for hash table module
rveeblefetzer Jan 25, 2017
a21cad5
Merge branch 'hash-table' of https://github.com/julienawilson/data-st…
rveeblefetzer Jan 25, 2017
5ca754b
set and hash functions
julienawilson Jan 25, 2017
0e23f34
Merge branch 'hash-table' of https://github.com/julienawilson/data-st…
rveeblefetzer Jan 25, 2017
1d25cbd
get for the hash function
julienawilson Jan 25, 2017
0ec88b5
added test for seting a number; fix typon in docstrings
rveeblefetzer Jan 25, 2017
201e12a
Merge branch 'hash-table' of https://github.com/julienawilson/data-st…
rveeblefetzer Jan 25, 2017
bf2a18b
added tests using unix dictionary list
rveeblefetzer Jan 25, 2017
7743b62
xor hash
julienawilson Jan 25, 2017
2c15414
added tests for xor with unix dict file
rveeblefetzer Jan 25, 2017
5eddf66
Added class docstring to module; added module info to README
rveeblefetzer Jan 25, 2017
b0852eb
adding initial module file
rveeblefetzer Jan 28, 2017
720ff5f
added class for trie trees and contains and insert methods
rveeblefetzer Jan 28, 2017
bc60e6d
tests for insert and contains
julienawilson Jan 28, 2017
fc3b20b
added Node class
rveeblefetzer Jan 28, 2017
4feee77
Merge branch 'trie' of https://github.com/julienawilson/data-structur…
julienawilson Jan 28, 2017
49038b7
more tests for insert and contains
julienawilson Jan 28, 2017
bd6e0ba
delete word
julienawilson Jan 28, 2017
87ce4b7
adding basic tests for remove method
rveeblefetzer Jan 28, 2017
3c40215
Merge branch 'trie' of https://github.com/julienawilson/data-structur…
rveeblefetzer Jan 28, 2017
86e9d10
delete raises error
julienawilson Jan 28, 2017
b9d74fa
Merge branch 'trie' of https://github.com/julienawilson/data-structur…
julienawilson Jan 28, 2017
269c22f
add another test for remove method
rveeblefetzer Jan 28, 2017
f90a8bc
Merge branch 'trie' of https://github.com/julienawilson/data-structur…
rveeblefetzer Jan 28, 2017
794e557
delete works on single word trees
julienawilson Jan 28, 2017
f184564
Merge branch 'trie' of https://github.com/julienawilson/data-structur…
julienawilson Jan 28, 2017
64e09fd
added size()
julienawilson Jan 28, 2017
4664d20
add more tests for remove method
rveeblefetzer Jan 28, 2017
f4d0471
Merge branch 'trie' of https://github.com/julienawilson/data-structur…
rveeblefetzer Jan 28, 2017
baddf49
debugging remove's helper method, tests
rveeblefetzer Jan 28, 2017
b7cfccf
deletes word parts and extensions
julienawilson Jan 29, 2017
474714a
add tests for size method
rveeblefetzer Jan 29, 2017
bdedcfe
Merge branch 'trie' of https://github.com/julienawilson/data-structur…
rveeblefetzer Jan 29, 2017
1f64fbb
adding docstrings, README info
rveeblefetzer Jan 29, 2017
416b704
adding initial traversal method
rveeblefetzer Jan 29, 2017
1e83927
added traversal and helper methods
rveeblefetzer Jan 29, 2017
cec048e
test for traversal
julienawilson Jan 29, 2017
a3f059b
Merge branch 'trie-traversal' of https://github.com/julienawilson/dat…
julienawilson Jan 29, 2017
7f92d13
test for traversal is a mess
julienawilson Jan 29, 2017
3ecd96d
draft function written
rveeblefetzer Jan 30, 2017
e431eaf
adding to repo
rveeblefetzer Jan 30, 2017
dd383b7
fixed insertion sort bug
julienawilson Jan 31, 2017
7f6208a
timit insertion sort
julienawilson Jan 31, 2017
2f3ebfa
adding first draft of quicksort
rveeblefetzer Feb 1, 2017
9084490
quicksort timit
julienawilson Feb 1, 2017
f51591f
test for quicksort
julienawilson Feb 1, 2017
c692652
Update README.md
julienawilson Feb 1, 2017
33d7ab6
Update README.md
julienawilson Feb 1, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ language: python
python:
- "2.7"
- "3.5"

install:
- pip install -e .[test]

Expand Down
39 changes: 38 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
[![Build Status](https://travis-ci.org/julienawilson/data-structures.svg?branch=master)](https://travis-ci.org/julienawilson/data-structures)

# Data Structures
=======
[![Build Status](https://travis-ci.org/julienawilson/data-structures.svg?branch=bst)](https://travis-ci.org/julienawilson/data-structures)

# data-structures
>>>>>>> 2f8af436a8271e1a77876030b065993c23274041
Patrick Saunders and Julien Wilson
<br>
Data Structures created in Python401
Expand All @@ -26,7 +31,7 @@ A linked list that points in both directions
A tree of nodes sorted by values less than and greater than root branching to the left and right, respectively.

Methods include:
* insert(self, val): Insert value into tree; if value already exists, ignore it.
* insert(self, val): Insert value into tree; if value already exists, ignore it. Method autobalances after insertion, and tree size increments by one.
* search(self, val): Return node containing that value, else None.
* size(self): Return number of nodes/vertices in tree, 0 if empty.
* depth(self): Return number of levels in tree. Tree with one value has depth of 0.
Expand All @@ -35,3 +40,35 @@ Methods include:
Trees that are higher on the left than the right should return a positive value;
trees that are higher on the right than the left should return a negative value;
an ideally-balanced tree should return 0.
* in_order(self): Return a generator that returns each node value from in-order traversal.
* pre_order(self): Return a generator that returns each node value from pre-order traversal.
* post_order(self): Return a generator that returns each node value from post_order traversal.
* breadth_first(self): Return a generator returns each node value from breadth-first traversal.
* delete(value): Delete a node's connections (edges), effectively deleting node. Method autobalances after deletion, and tree size decrements by one.

##Hash Table
Stores key-value pairs using a given hashing algorithm. Choices for hashing algorithms are additive hash and xor hash.
Additive hash sums the Unicode code point for each letter in the word or string, then calls modulo with the number of buckets in the table.
XOR hash runs exclusive or with the letters of the word or string.

Methods include:
set(key, value): Add a key-value pair to the hash table.
get(key): Retrieve a value for the given key.

##Trie Trees
Module is an implementation of a trie tree, using nested dictionaries instead of nodes.

Words branch out from root, with root's immediate children being
the initial letter of each word. Words can then branch from that initial,
as well as from initial substrings.

Methods include:
contains(word): Check to see whether a word is in the tree. O(k), where k is the length of the given word.
insert(word): Inserts a word into the trie tree. O(k), where k is the length of the given word.

##Quicksort
An Implementation of a Quicksort sorting algorithm.

Quicksort recursively divides the list in to two pieces around a pivot point, separating smaller and larger items, until the list is totally sorted.

When the script is run from the terminal, timit times 1000 executions of the code on a 200 item list. Timit does this three times and returns the results, in seconds.
158 changes: 144 additions & 14 deletions src/bst.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
"""Classes for binary search tree.

Methods include:
insert(self, val): Insert value into tree; if value already exists, ignore it.
search(self, val): Return node containing that value, else None.
size(self): Return number of nodes/vertices in tree, 0 if empty.
depth(self): Return number of levels in tree. Tree with one value has depth of 0.
contains(self, val): Return True if value is in tree, False if not.
balance(self): Return a positive or negative integer representing tree's balance.
insert(val): Insert value into tree; if value already exists, ignore it.
Method autobalances after insertion, and tree size increments by one.
search(val): Return node containing that value, else None.
size(): Return number of nodes/vertices in tree, 0 if empty.
depth(): Return number of levels in tree. Tree with one value has depth of 0.
contains(val): Return True if value is in tree, False if not.
balance(): Return a positive or negative integer representing tree's balance.
Trees that are higher on the left than the right should return a positive value;
trees that are higher on the right than the left should return a negative value;
an ideally-balanced tree should return 0.
in_order(): Return a generator that returns each node value from in-order traversal.
pre_order(): Return a generator that returns each node value from pre-order traversal.
post_order(): Return a generator that returns each node value from post_order traversal.
breadth_first(): Return a generator returns each node value from breadth-first traversal.
delete(value): Delete a node's connections (edges), effectively deleting node.
Method autobalances after deletion, and tree size decrements by one.

"""

from queue import Queue
Expand All @@ -18,11 +26,12 @@
class Node():
"""Node object for the binary search tree."""

def __init__(self, value, left=None, right=None):
def __init__(self, value, left=None, right=None, parent=None):
"""Instantiate a node object."""
self.value = value
self.left = left
self.right = right
self.parent = parent


class BinarySearchTree():
Expand All @@ -36,7 +45,7 @@ def __init__(self):
self._size = 0
self.root = None

def insert(self, value):
def insert(self, value, autobalance=True):
"""Insert a value in to the binary search tree."""
if self.root is None:
self.root = Node(value)
Expand All @@ -49,17 +58,21 @@ def insert(self, value):
current_node = current_node.left
else:
current_node.left = Node(value)
current_node.left.parent = current_node
self._size += 1
break
elif value > current_node.value:
if current_node.right:
current_node = current_node.right
else:
current_node.right = Node(value)
current_node.right.parent = current_node
self._size += 1
break
else:
break
if autobalance:
self._autobalance()

def search(self, value):
"""Search the Binary Search Tree for a value, return node or none."""
Expand Down Expand Up @@ -123,19 +136,96 @@ def contains(self, value):
else:
return False

def balance(self):
"""Return numerical representation of how balanced the tree is."""
if self.root.left:
depth_left = self.depth(self.root.left)
def balance(self, node='root'):
"""Return numerical representation of how balanced the tree (or branches) is."""
if node is None:
return 0
if node == 'root':
node = self.root
if node.left:
depth_left = self.depth(node.left) + 1
else:
depth_left = 0
if self.root.right:
depth_right = self.depth(self.root.right)
if node.right:
depth_right = self.depth(node.right) + 1
else:
depth_right = 0
balance = depth_right - depth_left
return balance

def _autobalance(self, node=None):
"""Make sure tree rebalances itself."""
if node is None:
node = self.root
nodes = self.post_order()
while True:
try:
this_node = next(nodes)
if abs(self.balance(this_node)) > 1:
self._rebalance(this_node)
except StopIteration:
break

# pass

def _rebalance(self, node):
"""Balance the given node."""
if self.balance(node) > 1:
if self.balance(node.right) >= 1:
self._rotate_left(node)
else:
self._rotate_right(node.right)
self._rotate_left(node)
elif self.balance(node) < -1:
if self.balance(node.left) <= -1:
self._rotate_right(node)
else:
self._rotate_left(node.left)
self._rotate_right(node)

def _rotate_right(self, node, holder_node=None):
"""Helper function to shift nodes clockwise."""
if node is None:
return
try:
if node.left.right:
holder_node = node.left.right
except AttributeError:
pass
if node.left:
node.left.parent = node.parent
node.left.right = node
if node.parent:
node.parent.left = node.left
node.parent = node.left
node.left = holder_node
if holder_node:
node.left.parent = node
if node == self.root:
self.root = node.parent

def _rotate_left(self, node, holder_node=None):
"""Helper function to shift nodes counterclockwise."""
if node is None:
return
try:
if node.right.left:
holder_node = node.right.left
except AttributeError:
pass

if node.right:
node.right.parent = node.parent
node.right.left = node
if node.parent:
node.parent.right = node.right
node.parent = node.right
node.right = holder_node
if holder_node:
node.right.parent = node
if node == self.root:
self.root = node.parent

def in_order(self):
"""Return generator that returns tree values one at a time using in-order traversal."""
stack = []
Expand Down Expand Up @@ -191,3 +281,43 @@ def breadth_first(self):
if current_node.right:
trav_list.enqueue(current_node.right)
yield current_node

def delete(self, value, autobalance=True):
"""Get rid of a node. Or at least its connection."""
target_node = self.search(value)
if not target_node:
return
if not (target_node.left or target_node.right):
if target_node.value > target_node.parent.value:
target_node.parent.right = None
else:
target_node.parent.left = None
elif not (target_node.left and target_node.right):
if target_node.left:
target_node.left.parent = target_node.parent
target_node.parent.left = target_node.left
else:
target_node.right.parent = target_node.parent
target_node.parent.right = target_node.right
else:
current_node = target_node.right
while current_node.left:
current_node = current_node.left
replace_node = current_node
self.delete(current_node.value)
self._size += 1 # undoes size change within delete
if target_node.parent:
replace_node.parent = target_node.parent
if replace_node.value < target_node.value:
target_node.parent.left = replace_node
else:
target_node.parent.right = replace_node
replace_node.left = target_node.left
replace_node.right = target_node.right
target_node.parent = None
target_node.left = None
target_node.right = None
self._size -= 1
if autobalance:
self._autobalance()

62 changes: 62 additions & 0 deletions src/hash_table.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"""Class for hash tables.

Choices for hashing algorithms are additive hash and xor hash.
Additive hash sums the Unicode code point for each letter in the word or string,
then calls modulo with the number of buckets in the table.
XOR hash runs exclusive or with the letters of the word or string.
Methods include:
set(key, value): Add a key-value pair to the hash table.
get(key): Retrieve a value for the given key.

"""



class HashTable(object):
"""Something something."""

def __init__(self, size, hash_alg='additive'):
"""Initialize a hash table."""
self._size = size
self.buckets = [[] for bucket in range(self._size)]
self._hash_alg = self._hash(hash_alg)

def _hash(self, hash_alg):
if hash_alg == 'additive':
return self._additive_hash
if hash_alg == 'xor':
return self._xor_hash
else:
raise ValueError("Please enter a valid hash algorithm. The options are 'additive' and 'xor'.")

def _additive_hash(self, word):
"""Return Additive hash value."""
return sum([ord(char) for char in list(word)]) % self._size

def _xor_hash(self, word):
"""Return a xor hash."""
hash_val = 0
for i in range(len(word)):
hash_val ^= ord(word[i])
return hash_val

def set(self, key, value):
"""Set a new key-value pair in the hash table."""
if type(key) is not str:
raise TypeError("Key for hash table must be a string.")
hash_val = self._hash_alg(key)
for pair in self.buckets[hash_val]:
if pair[0] == key:
pair[1] = value
return
self.buckets[hash_val].append([key, value])

def get(self, key):
"""Get the value from the hash table."""
if type(key) is not str:
raise TypeError("Key for hash table must be a string.")
hash_val = self._hash_alg(key)
for pair in self.buckets[hash_val]:
if pair[0] == key:
return pair[1]
return
38 changes: 38 additions & 0 deletions src/insertion_sort.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""Insertion sort."""


def insertion_sort(some_list):
"""It sorts."""
if not hasattr(some_list, "__iter__"):
raise(TypeError)
idx = 0
while idx < len(some_list) - 1:
if some_list[idx] > some_list[idx + 1]:
some_list[idx], some_list[idx + 1] = some_list[idx + 1], some_list[idx]
bw_list = some_list[:idx][::-1]
bw_idx = idx
for i in range(len(bw_list)):
# import pdb; pdb.set_trace()
if some_list[bw_idx] < bw_list[i]:
some_list[bw_idx], bw_list[i] = bw_list[i], some_list[bw_idx]
bw_idx -= 1
idx += 1
return some_list

if __name__ == "__main__":

import timeit
import random

def build_random_list():
"""Build a random list to sort."""
rand_list = [random.randint(0, 1000) for i in range(200)]
return rand_list

lst = build_random_list()

print(timeit.repeat(stmt='insertion_sort(lst)',
setup='from __main__ import insertion_sort, lst, random', repeat=3,
number=1000
)
)
Loading