Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #49 circular linked list #115

Merged
Merged
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__)
220 changes: 219 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,217 @@ def __getitem__(self, index):
current_node = current_node.next
counter += 1
return current_node

class SinglyCircularLinkedList(SinglyLinkedList):
"""
Represents Singly Circular Linked List.

Parent Class
============

SinglyLinkedList.
prshnt19 marked this conversation as resolved.
Show resolved Hide resolved

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))