Skip to content

Commit

Permalink
feat(circular-linked-list): josephus circle
Browse files Browse the repository at this point in the history
  • Loading branch information
BrianLusina committed May 22, 2024
1 parent a01fa48 commit 0ee4e06
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 2 deletions.
19 changes: 19 additions & 0 deletions algorithms/josephus_circle/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Josephus Circle

Children often play a counting-out game to randomly select one person from the group by singing a rhyme. The purpose is
to select one person, either as a straightforward winner, or as someone who is eliminated.

Josephus problem is related to this concept. In this problem, people are standing in one circle waiting to be executed.
Following points list the specifications of Josephus problem:

The counting out begins at a specified point in a circle and continues around the circle in a fixed direction.

In each step, a certain number of people are skipped and the next person is executed.

For example, if we have 𝑛 people, and 𝑘-1 people are skipped every time, it means that the
𝑘th person is executed. Here, 𝑘 is the step-size.

## Reference

- https://en.wikipedia.org/wiki/Josephus_problem
-
18 changes: 18 additions & 0 deletions algorithms/josephus_circle/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from datastructures.linked_lists.circular import CircularLinkedList
from datastructures.linked_lists.circular.node import CircularNode


def josephus_circle(circular_list: CircularLinkedList, step: int) -> CircularNode:
current = circular_list.head

length = len(circular_list)
while length > 1:
count = 1
while count != step:
current = current.next
count += 1
circular_list.delete_node(current)
current = current.next
length -= 1

return current
22 changes: 22 additions & 0 deletions algorithms/josephus_circle/test_josephus_circle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import unittest
from datastructures.linked_lists.circular import CircularLinkedList
from datastructures.linked_lists.circular.node import CircularNode
from . import josephus_circle


class JosephusCircularTestCase(unittest.TestCase):
def test_1(self):
"""should run through the circle of 1-2-3-4 with a step of 2 remaining with 1"""
data = [1, 2, 3, 4]
circular_linked_list = CircularLinkedList()
for d in data:
circular_linked_list.append(d)

step = 2
expected = CircularNode(1)
actual = josephus_circle(circular_linked_list, step)
self.assertEqual(expected, actual)


if __name__ == '__main__':
unittest.main()
45 changes: 43 additions & 2 deletions datastructures/linked_lists/circular/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,49 @@ def shift(self):
def pop(self) -> Optional[Node]:
pass

def delete_node(self, n: Node):
pass
def delete_node(self, node_: CircularNode):
if self.head:
# if the head node matches the node we are looking for
if self.head == node_:
# set the current pointer to the head node. This will be used to track the last node as the pointer
# moves through the list
current = self.head
# move through the list until we reach the pointer that points batck to the head node.
while current.next != self.head:
current = current.next

# if the head node equals the next node, that means that this linked list has a length of 1, i.e. just 1
# node. The head node can be set to None
if self.head == self.head.next:
self.head = None
else:
# set the current pointer to point to the current head's next
current.next = self.head.next
# set the head to now become the next node
self.head = self.head.next
else:
# we have a situation where the head node's key is not equal to the head node, therefore, we need to
# traverse the list to find the first node whose key matches the given key. Setting current to the head
# node acts as the pointer that we keep track of
current = self.head
# previous pointer helps to keep track of the previous node as we traverse, it is initially set to None
previous: Optional[CircularNode] = None

# we iterate through the linked list as long as the next pointer of the current head is not equal to
# the head node. This is to avoid an infinite loop as this is a circular linked list.
while current.next != self.head:
# we set the previous pointer to the current node to keep track of the node before we reset the
# current pointer to the next node
previous = current
# move the current pointer to the next node
current = current.next
# if the current node's key is equal to the key we are searching for
if current == node_:
# we set the previous node's next pointer to point to the current node's next pointer.
# Essentially removing the current node from the list
previous.next = current.next
# set the current node to the current's next node
current = current.next

def delete_node_at_position(self, position: int):
pass
Expand Down

0 comments on commit 0ee4e06

Please sign in to comment.