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__)
222 changes: 221 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,219 @@ 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
.. [2] https://www.geeksforgeeks.org/circular-singly-linked-list-insertion/
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
.. [2] https://www.geeksforgeeks.org/circular-singly-linked-list-insertion/

Copy link
Member Author

Choose a reason for hiding this comment

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

The wiki page does not have enough info so I added other references.

Copy link
Member Author

Choose a reason for hiding this comment

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

The info on the Wiki is not enough. Should I add a reference from other sites or leave it as it is?

Copy link
Member

Choose a reason for hiding this comment

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

You can add links to university lectures.

Copy link
Member Author

@prshnt19 prshnt19 Mar 3, 2020

Choose a reason for hiding this comment

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

I have updated Wiki References.


"""

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/Linked_list#Circular_linked_list
.. [2] https://www.geeksforgeeks.org/doubly-circular-linked-list-set-1-introduction-and-insertion/

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