Skip to content

Commit 0ee4e06

Browse files
committed
feat(circular-linked-list): josephus circle
1 parent a01fa48 commit 0ee4e06

File tree

4 files changed

+102
-2
lines changed

4 files changed

+102
-2
lines changed

algorithms/josephus_circle/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Josephus Circle
2+
3+
Children often play a counting-out game to randomly select one person from the group by singing a rhyme. The purpose is
4+
to select one person, either as a straightforward winner, or as someone who is eliminated.
5+
6+
Josephus problem is related to this concept. In this problem, people are standing in one circle waiting to be executed.
7+
Following points list the specifications of Josephus problem:
8+
9+
The counting out begins at a specified point in a circle and continues around the circle in a fixed direction.
10+
11+
In each step, a certain number of people are skipped and the next person is executed.
12+
13+
For example, if we have 𝑛 people, and 𝑘-1 people are skipped every time, it means that the
14+
𝑘th person is executed. Here, 𝑘 is the step-size.
15+
16+
## Reference
17+
18+
- https://en.wikipedia.org/wiki/Josephus_problem
19+
-
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
from datastructures.linked_lists.circular import CircularLinkedList
2+
from datastructures.linked_lists.circular.node import CircularNode
3+
4+
5+
def josephus_circle(circular_list: CircularLinkedList, step: int) -> CircularNode:
6+
current = circular_list.head
7+
8+
length = len(circular_list)
9+
while length > 1:
10+
count = 1
11+
while count != step:
12+
current = current.next
13+
count += 1
14+
circular_list.delete_node(current)
15+
current = current.next
16+
length -= 1
17+
18+
return current
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import unittest
2+
from datastructures.linked_lists.circular import CircularLinkedList
3+
from datastructures.linked_lists.circular.node import CircularNode
4+
from . import josephus_circle
5+
6+
7+
class JosephusCircularTestCase(unittest.TestCase):
8+
def test_1(self):
9+
"""should run through the circle of 1-2-3-4 with a step of 2 remaining with 1"""
10+
data = [1, 2, 3, 4]
11+
circular_linked_list = CircularLinkedList()
12+
for d in data:
13+
circular_linked_list.append(d)
14+
15+
step = 2
16+
expected = CircularNode(1)
17+
actual = josephus_circle(circular_linked_list, step)
18+
self.assertEqual(expected, actual)
19+
20+
21+
if __name__ == '__main__':
22+
unittest.main()

datastructures/linked_lists/circular/__init__.py

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,49 @@ def shift(self):
8686
def pop(self) -> Optional[Node]:
8787
pass
8888

89-
def delete_node(self, n: Node):
90-
pass
89+
def delete_node(self, node_: CircularNode):
90+
if self.head:
91+
# if the head node matches the node we are looking for
92+
if self.head == node_:
93+
# set the current pointer to the head node. This will be used to track the last node as the pointer
94+
# moves through the list
95+
current = self.head
96+
# move through the list until we reach the pointer that points batck to the head node.
97+
while current.next != self.head:
98+
current = current.next
99+
100+
# if the head node equals the next node, that means that this linked list has a length of 1, i.e. just 1
101+
# node. The head node can be set to None
102+
if self.head == self.head.next:
103+
self.head = None
104+
else:
105+
# set the current pointer to point to the current head's next
106+
current.next = self.head.next
107+
# set the head to now become the next node
108+
self.head = self.head.next
109+
else:
110+
# we have a situation where the head node's key is not equal to the head node, therefore, we need to
111+
# traverse the list to find the first node whose key matches the given key. Setting current to the head
112+
# node acts as the pointer that we keep track of
113+
current = self.head
114+
# previous pointer helps to keep track of the previous node as we traverse, it is initially set to None
115+
previous: Optional[CircularNode] = None
116+
117+
# we iterate through the linked list as long as the next pointer of the current head is not equal to
118+
# the head node. This is to avoid an infinite loop as this is a circular linked list.
119+
while current.next != self.head:
120+
# we set the previous pointer to the current node to keep track of the node before we reset the
121+
# current pointer to the next node
122+
previous = current
123+
# move the current pointer to the next node
124+
current = current.next
125+
# if the current node's key is equal to the key we are searching for
126+
if current == node_:
127+
# we set the previous node's next pointer to point to the current node's next pointer.
128+
# Essentially removing the current node from the list
129+
previous.next = current.next
130+
# set the current node to the current's next node
131+
current = current.next
91132

92133
def delete_node_at_position(self, position: int):
93134
pass

0 commit comments

Comments
 (0)