Skip to content

Commit

Permalink
Added SinglyCircularLinkedList and DoublyCircularLinkedList (#115)
Browse files Browse the repository at this point in the history
  • Loading branch information
prshnt19 committed Mar 4, 2020
1 parent 94a69e9 commit 4d35068
Show file tree
Hide file tree
Showing 3 changed files with 287 additions and 3 deletions.
4 changes: 3 additions & 1 deletion pydatastructs/linear_data_structures/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

from .linked_lists import (
SinglyLinkedList,
DoublyLinkedList
DoublyLinkedList,
SinglyCircularLinkedList,
DoublyCircularLinkedList
)
__all__.extend(linked_lists.__all__)
216 changes: 215 additions & 1 deletion pydatastructs/linear_data_structures/linked_lists.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

__all__ = [
'SinglyLinkedList',
'DoublyLinkedList'
'DoublyLinkedList',
'SinglyCircularLinkedList',
'DoublyCircularLinkedList'
]

class LinkedList(object):
Expand All @@ -27,6 +29,8 @@ def __str__(self):
while current_node is not None:
elements.append(current_node.data)
current_node = current_node.next
if current_node == self.head:
break
return str(elements)

class DoublyLinkedList(LinkedList):
Expand Down Expand Up @@ -508,3 +512,213 @@ def __getitem__(self, index):
current_node = current_node.next
counter += 1
return current_node

class SinglyCircularLinkedList(SinglyLinkedList):
"""
Represents Singly Circular Linked List.
Examples
========
>>> from pydatastructs import SinglyCircularLinkedList
>>> scll = SinglyCircularLinkedList()
>>> scll.append(6)
>>> scll[0].data
6
>>> scll.head.data
6
>>> scll.append(5)
>>> scll.append_left(2)
>>> print(scll)
[2, 6, 5]
>>> scll[0].data = 7.2
>>> scll.extract(1).data
6
>>> print(scll)
[7.2, 5]
References
==========
.. [1] https://en.wikipedia.org/wiki/Linked_list#Circular_linked_list
"""

def insert_after(self, prev_node, data):
"""
Inserts a new node after the prev_node.
Parameters
==========
prev_node: LinkedListNode
The node after which the
new node is to be inserted.
data
Any valid data to be stored in the node.
"""
super(SinglyCircularLinkedList, self).insert_after(prev_node, data)
if prev_node.next.next == self.head:
self.tail = prev_node.next

def insert_at(self, index, data):
"""
Inserts a new node at the input index.
Parameters
==========
index: int
An integer satisfying python indexing properties.
data
Any valid data to be stored in the node.
"""
super(SinglyCircularLinkedList, self).insert_at(index, data)
if self.size == 1:
self.head.next = self.head
new_node = self.__getitem__(index)
if index == 0:
self.tail.next = new_node
if new_node.next == self.head:
self.tail = new_node

def extract(self, index):
"""
Extracts the node at the index of the list.
Parameters
==========
index: int
An integer satisfying python indexing properties.
Returns
=======
current_node: LinkedListNode
The node at index i.
"""
node = super(SinglyCircularLinkedList, self).extract(index)
if self.tail is None:
self.head = None
elif index == 0:
self.tail.next = self.head
return node

class DoublyCircularLinkedList(DoublyLinkedList):
"""
Represents Doubly Circular Linked List
Examples
========
>>> from pydatastructs import DoublyCircularLinkedList
>>> dcll = DoublyCircularLinkedList()
>>> dcll.append(6)
>>> dcll[0].data
6
>>> dcll.head.data
6
>>> dcll.append(5)
>>> dcll.append_left(2)
>>> print(dcll)
[2, 6, 5]
>>> dcll[0].data = 7.2
>>> dcll.extract(1).data
6
>>> print(dcll)
[7.2, 5]
References
==========
.. [1] https://en.wikipedia.org/wiki/Doubly_linked_list#Circular_doubly_linked_lists
"""
def insert_after(self, prev_node, data):
"""
Inserts a new node after the prev_node.
Parameters
==========
prev_node: LinkedListNode
The node after which the
new node is to be inserted.
data
Any valid data to be stored in the node.
"""
super(DoublyCircularLinkedList, self).insert_after(prev_node, data)
if prev_node.next.next == self.head:
self.tail = prev_node.next

def insert_before(self, next_node, data):
"""
Inserts a new node before the next_node.
Parameters
==========
next_node: LinkedListNode
The node before which the
new node is to be inserted.
data
Any valid data to be stored in the node.
"""
super(DoublyCircularLinkedList, self).insert_before(next_node,data)
if next_node == self.head:
self.head = next_node.prev

def insert_at(self, index, data):
"""
Inserts a new node at the input index.
Parameters
==========
index: int
An integer satisfying python indexing properties.
data
Any valid data to be stored in the node.
"""
super(DoublyCircularLinkedList, self).insert_at(index, data)
if self.size == 1:
self.head.next = self.head
self.head.prev = self.head
new_node = self.__getitem__(index)
if index == 0:
self.tail.next = new_node
new_node.prev = self.tail
if new_node.next == self.head:
self.tail = new_node
new_node.next = self.head
self.head.prev = new_node

def extract(self, index):
"""
Extracts the node at the index of the list.
Parameters
==========
index: int
An integer satisfying python indexing properties.
Returns
=======
current_node: LinkedListNode
The node at index i.
"""
node = super(DoublyCircularLinkedList, self).extract(index)
if self.tail is None:
self.head = None
elif index == 0:
self.tail.next = self.head
return node
70 changes: 69 additions & 1 deletion pydatastructs/linear_data_structures/tests/test_linked_lists.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from pydatastructs.linear_data_structures import DoublyLinkedList, SinglyLinkedList
from pydatastructs.linear_data_structures import DoublyLinkedList, SinglyLinkedList, SinglyCircularLinkedList, DoublyCircularLinkedList
from pydatastructs.utils.raises_util import raises
import copy, random

Expand Down Expand Up @@ -69,3 +69,71 @@ def test_SinglyLinkedList():
sll_copy.extract(index)
assert str(sll_copy) == "[]"
assert raises(ValueError, lambda: sll_copy.extract(1))

def test_SinglyCircularLinkedList():
random.seed(1000)
scll = SinglyCircularLinkedList()
assert raises(IndexError, lambda: scll[2])
scll.append_left(5)
scll.append(1)
scll.append_left(2)
scll.append(3)
scll.insert_after(scll[1], 4)
scll.insert_after(scll[-1], 6)
scll.insert_at(0, 2)
scll.insert_at(-1, 9)
scll.extract(2)
scll.extract(0)
scll.extract(-1)
scll[-2].data = 0
assert str(scll) == "[2, 4, 1, 0, 9]"
assert len(scll) == 5
assert raises(IndexError, lambda: scll.insert_at(6, None))
assert raises(IndexError, lambda: scll.extract(20))
scll_copy = copy.deepcopy(scll)
for i in range(len(scll)):
if i%2 == 0:
scll.pop_left()
else:
scll.pop_right()
assert str(scll) == "[]"
for _ in range(len(scll_copy)):
index = random.randint(0, len(scll_copy) - 1)
scll_copy.extract(index)
assert str(scll_copy) == "[]"
assert raises(ValueError, lambda: scll_copy.extract(1))

def test_DoublyCircularLinkedList():
random.seed(1000)
dcll = DoublyCircularLinkedList()
assert raises(IndexError, lambda: dcll[2])
dcll.append_left(5)
dcll.append(1)
dcll.append_left(2)
dcll.append(3)
dcll.insert_after(dcll[-1], 4)
dcll.insert_after(dcll[2], 6)
dcll.insert_before(dcll[4], 1)
dcll.insert_before(dcll[0], 7)
dcll.insert_at(0, 2)
dcll.insert_at(-1, 9)
dcll.extract(2)
dcll.extract(0)
dcll.extract(-1)
dcll[-2].data = 0
assert str(dcll) == "[7, 5, 1, 6, 1, 0, 9]"
assert len(dcll) == 7
assert raises(IndexError, lambda: dcll.insert_at(8, None))
assert raises(IndexError, lambda: dcll.extract(20))
dcll_copy = copy.deepcopy(dcll)
for i in range(len(dcll)):
if i%2 == 0:
dcll.pop_left()
else:
dcll.pop_right()
assert str(dcll) == "[]"
for _ in range(len(dcll_copy)):
index = random.randint(0, len(dcll_copy) - 1)
dcll_copy.extract(index)
assert str(dcll_copy) == "[]"
assert raises(ValueError, lambda: dcll_copy.extract(1))

0 comments on commit 4d35068

Please sign in to comment.