Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
d44d98f
creating first draft of linked list file.
JSchatzman Dec 12, 2016
34e4d4a
tests for node and linked_list class creation
julienawilson Dec 12, 2016
d144503
adding pop and push with testing
JSchatzman Dec 12, 2016
c306cb1
adding search with tests
JSchatzman Dec 12, 2016
319d906
test for remove()
julienawilson Dec 12, 2016
3cf09b7
finished linked_list and testing with display()
julienawilson Dec 12, 2016
d8fe873
adding final tests
JSchatzman Dec 13, 2016
9682aac
gitignore fix
julienawilson Dec 13, 2016
3de31ae
adding content to r readme
JSchatzman Dec 13, 2016
62beee9
adding content to readme
JSchatzman Dec 13, 2016
5d9137c
Merge branch 'linked_list' of https://github.com/JSchatzman/data_stru…
JSchatzman Dec 13, 2016
eab1059
adding readme content
JSchatzman Dec 13, 2016
c3eb6dd
fixing readme
JSchatzman Dec 13, 2016
c2f92af
updated setup file, testing for stack init and push
julienawilson Dec 13, 2016
52fc1de
Merge branch 'stack' of https://github.com/JSchatzman/data_structures…
JSchatzman Dec 13, 2016
f5783ff
commiting finals tests for stack
JSchatzman Dec 13, 2016
5742fe7
small linter fix
julienawilson Dec 13, 2016
ef25a88
Update README.md
julienawilson Dec 13, 2016
f816975
updated linked list and test to allow empty
julienawilson Dec 14, 2016
127fd29
test removing tail node
julienawilson Dec 14, 2016
974cbd8
Merge branch 'linked_list' of https://github.com/JSchatzman/data_stru…
JSchatzman Dec 14, 2016
ea3d759
change stack to use composition
JSchatzman Dec 14, 2016
1e1b711
dll init, push and append with tests
julienawilson Dec 14, 2016
4278df6
dll pop with test
julienawilson Dec 14, 2016
98b492e
adding dll with tests
JSchatzman Dec 14, 2016
5e5f97b
used fixtures in testing
julienawilson Dec 16, 2016
35ca79d
changed error messages to actual error raising
julienawilson Dec 16, 2016
d52fc51
redoing tests
JSchatzman Dec 16, 2016
abd7ea5
update terminology on stack pop
julienawilson Dec 16, 2016
50a6f30
improving test file format
JSchatzman Dec 16, 2016
92527b8
Merge branch 'stack' of https://github.com/JSchatzman/data_structures…
julienawilson Dec 18, 2016
6ed3652
llist updates
julienawilson Dec 27, 2016
e085be0
remove() edits
julienawilson Dec 27, 2016
68e2840
fix typo
JSchatzman Dec 27, 2016
fdf4a2c
fix remove
JSchatzman Dec 27, 2016
54961fb
adding more tests
JSchatzman Dec 27, 2016
7f6b816
changed tests to use fixtures
julienawilson Dec 28, 2016
dc108d4
clean up ll.py
JSchatzman Dec 28, 2016
864cf8e
made tests fixtures
julienawilson Dec 28, 2016
d7e3e24
resolve conflict
JSchatzman Dec 28, 2016
8d9aa05
fix another conflict
JSchatzman Dec 28, 2016
2eccafd
new linked list for stack
JSchatzman Dec 28, 2016
de9835c
use fixtures in testing
julienawilson Dec 28, 2016
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
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ var/
*.egg-info/
.installed.cfg
*.egg
data_structures_venv/
bin/
lib64
pyvenv.cfg
share/
pip-selfcheck.json


# PyInstaller
# Usually these files are written by a python script from a template
Expand Down
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
# data_structures
# data_structures

##### This repository contains python implementations of various fundamental abstract data structures. These include:


##### 1. Linked List (src/linked_list.py)

##### 2. Stack (src/stack.py)

15 changes: 15 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""The setup for Mailroom distribution."""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mailroom? I just wanted my fancy data structures!


from setuptools import setup

setup(
name='data_structures',
description='Implementation of Data Structures.',
version=0.1,
author='Jordan Schatzman, Julien Wilson',
author_email='j.schatzman@outlook.com, julienawilson@gmail.com',
license='MIT',
package_dir={'': 'src'},
py_modules=['linked_list', 'stack'],
extras_require={'test': ['pytest', 'pytest-watch', 'pytest-cov', 'tox']},
)
94 changes: 94 additions & 0 deletions src/dll.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
"""Implementation of Doubly Linked List data type."""


class DoublyLinkedList(object):
"""Class representation of doubly linked list."""

def __init__(self, iterable=None):
"""Instantiate linked list."""
self.head_node = None
self.tail_node = None
self.length = 0
try:
for item in iterable:
self.push(item)
except TypeError:
if iterable:
print("Please only enter iterable values")

def push(self, contents):
"""Add node to this dll."""
if self.length == 0:
self.head_node = Node(contents, None, None)
self.tail_node = self.head_node
else:
self.head_node = Node(contents, self.head_node, None)
self.length += 1

def append(self, contents):
"""Add node to this dll."""
if self.length == 0:
self.tail_node = Node(contents, None, None)
self.head_node = self.tail_node
else:
self.tail_node = Node(contents, None, self.tail_node)
self.length += 1

def pop(self):
"""Remove and return the current head node."""
if not self.head_node:
print("Linked list is already empty")
return
old_head_node = self.head_node
self.head_node = self.head_node.next_node
self.length -= 1
return old_head_node

def shift(self):
"""Remove the end of the dll."""
if not self.tail_node:
print("Linked list is already empty")
return
old_tail_node = self.tail_node
self.tail_node = self.tail_node.previous_node
self.length -= 1
return old_tail_node

def remove(self, contents):
"""Remove the first node with input contents if it exists."""
if not self.length:
raise NameError('This dll is empty.')
if self.head_node.contents == contents:
if self.length == 1:
self.head_node = None
self.tail_node = None
else:
self.head_node = self.head_node.next_node
self.head_node.previous_node = None
self.length -= 1
return
test_node = self.head_node
while test_node.contents != contents and test_node.next_node:
last_node = test_node
test_node = test_node.next_node
if test_node.contents == contents and not test_node.next_node:
last_node.next_node = None
self.tail_node = last_node
self.length -= 1
return
elif test_node.contents == contents:
last_node.next_node = test_node.next_node
test_node.next_node.previous_node = last_node
self.length -= 1
return
raise NameError('{0} is not in the dll'.format(contents))


class Node(object):
"""Class representation of doubly linked list node."""

def __init__(self, contents, next_node, previous_node):
"""Instantiate doubly linked list node."""
self.contents = contents
self.next_node = next_node
self.previous_node = previous_node
84 changes: 84 additions & 0 deletions src/linked_list.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
"""Implementation of Linked_List data type."""


class LinkedList(object):
"""Class representation of linked list."""

def __init__(self, iterable=None):
"""Instantiate linked list."""
self.head_node = None
self.length = 0
try:
for item in iterable:
self.push(item)
except TypeError:
if iterable:
raise TypeError("Please only enter iterable values")

def push(self, contents):
"""Add node to this linked list."""
self.head_node = Node(contents, self.head_node)
self.length += 1

def pop(self):
"""Remove and return the current head node."""
if not self.head_node:
raise IndexError("List is already empty")
old_head_node = self.head_node
self.head_node = self.head_node.next_node
self.length -= 1
return old_head_node.contents

def size(self):
"""Return the current size of this linked list."""
return self.length

def search(self, search_value):
"""Return the node with the searched contents if found."""
if self.length:
if search_value == self.head_node.contents:
return self.head_node
current_node = self.head_node
while current_node.contents != search_value:
if current_node.next_node is None:
return None
current_node = current_node.next_node
return current_node
else:
return None

def remove(self, remove_value):
"""Remove a node from linked list."""
last_node = None
current_node = self.head_node
while current_node:
if current_node.contents == remove_value:
if last_node:
last_node.next_node = current_node.next_node
else:
self.head_node = current_node.next_node
self.length -= 1
return
last_node = current_node
current_node = current_node.next_node

def display(self):
"""Return the tuple of all values in linked list."""
if self.length == 0:
return None
else:
new_list = [self.head_node.contents]
current_node = self.head_node
while current_node.next_node is not None:
current_node = current_node.next_node
new_list.append(current_node.contents)
return str(tuple(new_list))


class Node(object):
"""Class representation of linked list node."""

def __init__(self, contents, next_node):
"""Instantiate linked list node."""
self.contents = contents
self.next_node = next_node
24 changes: 24 additions & 0 deletions src/stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Implementation of Stack data type."""

from linked_list import LinkedList


class Stack(object):
"""Class representation of a stack."""

def __init__(self, iterable=None):
"""Instantiate stack."""
self.linked_list = LinkedList(iterable)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good use of composition!

self.length = self.linked_list.length
self.head_node = self.linked_list.head_node

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, since you have all of the linked lists's functionality here, do you really need to assign a head_node variable? What purpose is it serving?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we want to check the value of the head node, we need to assign it in the Stack, correct?

I suppose we could get it using my_stack.linked_list.headnode, but isnt that kind of ugly?


def push(self, contents):
"""Add node to this stack."""
self.linked_list.push(contents)
self.head_node = self.linked_list.head_node

def pop(self):
"""Remove and return the current head node."""
old_head_node_value = self.linked_list.pop()
self.head_node = self.linked_list.head_node
return old_head_node_value
108 changes: 108 additions & 0 deletions src/test_dll.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""Tests for dll.py."""

import pytest


@pytest.fixture
def sample_dll():
"""Create testing dlls."""
from dll import DoublyLinkedList
one_dll = DoublyLinkedList([1])
empty_dll = DoublyLinkedList()
new_dll = DoublyLinkedList([1, 2, 3, 4, 5])
return one_dll, empty_dll, new_dll


def test_node_init():
"""Test node class init."""
from dll import Node
new_node = Node(0, None, None)
assert new_node.contents == 0
assert new_node.next_node is None
assert new_node.previous_node is None


def test_dll_init():
"""Test for dll init."""
from dll import DoublyLinkedList
one_dll, empty_dll, new_dll = sample_dll()
assert empty_dll.length == 0
assert empty_dll.head_node is None
assert empty_dll.tail_node is None


def test_dll_push():
"""Test for dll push."""
from dll import DoublyLinkedList
one_dll, empty_dll, new_dll = sample_dll()
new_dll.push("new")
assert new_dll.length == 6
assert new_dll.head_node.contents == "new"
empty_dll.push("second")
assert empty_dll.length == 1
assert empty_dll.head_node.contents == "second"


def test_dll_append():
"""Test for dll push."""
from dll import DoublyLinkedList
one_dll, empty_dll, new_dll = sample_dll()
empty_dll.append("new")
assert empty_dll.length == 1
assert empty_dll.tail_node.contents == "new"
assert empty_dll.head_node.contents == "new"
new_dll.append("second")
assert new_dll.length == 6
assert new_dll.tail_node.contents == "second"
one_dll.append('2')
assert one_dll.length == 2
assert one_dll.tail_node.contents == '2'
assert one_dll.head_node.contents == 1


def test_dll_pop():
"""Test for dll pop."""
from dll import DoublyLinkedList
one_dll, empty_dll, new_dll = sample_dll()
assert new_dll.pop().contents == 5
assert new_dll.length == 4
assert one_dll.pop().contents == 1
assert one_dll.length == 0


def test_dll_shift():
"""Test for dll shift."""
from dll import DoublyLinkedList
one_dll, empty_dll, new_dll = sample_dll()
assert new_dll.shift().contents == 1
assert empty_dll.shift() is None
assert one_dll.shift().contents == 1
assert one_dll.length == 0


def test_dll_remove():
"""Test for dll remove."""
from dll import DoublyLinkedList
one_dll, empty_dll, new_dll = sample_dll()
new_dll.remove(3)
assert new_dll.length == 4
assert new_dll.head_node.next_node.next_node.contents == 2
assert new_dll.head_node.next_node.next_node.previous_node.contents == 4
try:
new_dll.remove(10)
except NameError:
assert True
new_dll.remove(5)
assert new_dll.head_node.contents == 4
new_dll.remove(1)
assert new_dll.tail_node.contents == 2
empty_dll = DoublyLinkedList()
try:
empty_dll.remove(100)
except NameError:
assert True
one_dll = DoublyLinkedList([1])
one_dll.remove(1)
assert one_dll.head_node is None
assert one_dll.tail_node is None
assert one_dll.length == 0
Loading