1 changed files with 213 additions and 0 deletions
@ -0,0 +1,213 @@
@@ -0,0 +1,213 @@
|
||||
#!/usr/bin/env python |
||||
|
||||
""" |
||||
josephus.py |
||||
|
||||
Solve the Josephus problem with a doubly linked list |
||||
""" |
||||
|
||||
|
||||
class Josephus(object): |
||||
"""Josephus class defines a Josephus |
||||
problem of size n. It is a stateful |
||||
object that takes two input params |
||||
n (size of circle) and m (number of |
||||
steps). It has a method that will |
||||
generate the outcome of the Josephus |
||||
problem in the form of a list of |
||||
integers. |
||||
|
||||
Example: |
||||
Input: n = 8, m = 4 |
||||
Output: 54613872 |
||||
Explanation: |
||||
- position 1 is the 5th position visited |
||||
- position 2 is the 4th position visited |
||||
- etc. |
||||
""" |
||||
def __init__(self, n, m): |
||||
self.n = n |
||||
self.m = m |
||||
|
||||
# Initialize the list |
||||
nums = range(1,n+1) |
||||
self.list = DLC() |
||||
self.list.add_iter(nums) |
||||
|
||||
# Just checking |
||||
assert len(self.list)==n |
||||
|
||||
def simulate(self): |
||||
# Actually simulate the problem solution, |
||||
# plucking off one list item at a time |
||||
permutation = [] |
||||
i = 1 |
||||
|
||||
# Make sure we start at 0, officially |
||||
while len(self.list)>0: |
||||
self.list.sneak(self.m-1) |
||||
h = self.list.pop() |
||||
permutation.append((h,i)) |
||||
i += 1 |
||||
return permutation |
||||
|
||||
class Node(object): |
||||
def __init__(self, value): |
||||
self.prev = None |
||||
self.next = None |
||||
self.value = value |
||||
|
||||
class DLC(object): |
||||
"""Doubly-Linked Circular List DLC |
||||
""" |
||||
def __init__(self): |
||||
self.root = None |
||||
self.size = 0 |
||||
|
||||
def __len__(self): |
||||
return self.size |
||||
|
||||
def __str__(self): |
||||
if self.root==None: |
||||
return "" |
||||
else: |
||||
sc = [] |
||||
n = self.size |
||||
arrow = " -> " |
||||
runner = self.root |
||||
sc.append(str(runner.value)) |
||||
sc.append(arrow) |
||||
for _ in range(n-1): |
||||
runner = runner.next |
||||
sc.append(str(runner.value)) |
||||
sc.append(arrow) |
||||
return "".join(sc) |
||||
|
||||
|
||||
def add(self,item): |
||||
"""Add a single item to the list |
||||
""" |
||||
e = Node(item) |
||||
self._add_front_node(e) |
||||
self.size += 1 |
||||
|
||||
def add_iter(self,items): |
||||
"""Add all items in an iterable object. |
||||
This calls reversed() on the input |
||||
so that the order in the list matches |
||||
the order in the iterable object. |
||||
""" |
||||
for item in reversed(items): |
||||
e = Node(item) |
||||
self._add_front_node(e) |
||||
self.size += 1 |
||||
|
||||
def pop(self): |
||||
"""Pop the front node off |
||||
and return it. |
||||
""" |
||||
e = self._remove_front_node() |
||||
self.size -= 1 |
||||
return e.value |
||||
|
||||
def sneak(self,s): |
||||
"""Sneak the root pointer ahead |
||||
by k units. |
||||
""" |
||||
if self.size>0: |
||||
if s > 0: |
||||
for _ in range(s): |
||||
self.root = self.root.next |
||||
else: |
||||
for _ in range(abs(s)): |
||||
self.root = self.root.prev |
||||
|
||||
def _add_front_node(self,node): |
||||
"""Private method: add a front node |
||||
""" |
||||
if self.root == None: |
||||
# Fresh list |
||||
self.root = node |
||||
self.root.next = self.root |
||||
self.root.prev = self.root |
||||
|
||||
else: |
||||
# Insert into existing circle |
||||
|
||||
# Get pointers |
||||
new_front = node |
||||
old_front = self.root |
||||
tail = self.root.prev |
||||
|
||||
# Link new_front and old_front |
||||
new_front.next = old_front |
||||
old_front.prev = new_front |
||||
|
||||
# Link tail and new front |
||||
tail.next = new_front |
||||
new_front.prev = tail |
||||
|
||||
# Set new root |
||||
self.root = new_front |
||||
|
||||
|
||||
def _remove_front_node(self): |
||||
"""Private method: remove the front node |
||||
""" |
||||
if self.root is None: |
||||
# Empty list |
||||
return None |
||||
|
||||
elif self.root.next is self.root: |
||||
# One-element list |
||||
r = self.root |
||||
self.root = None |
||||
return r |
||||
|
||||
else: |
||||
|
||||
# Get pointers |
||||
ret = self.root |
||||
new_front = self.root.next |
||||
tail = self.root.prev |
||||
|
||||
# Unlink ret |
||||
ret.next = None |
||||
ret.prev = None |
||||
|
||||
# Link tail and new_front |
||||
tail.next = new_front |
||||
new_front.prev = tail |
||||
|
||||
# Set new root |
||||
self.root = new_front |
||||
|
||||
return ret |
||||
|
||||
|
||||
def josephus(): |
||||
|
||||
n = 8 |
||||
m = 4 |
||||
|
||||
J = Josephus(n,m) |
||||
perm = J.simulate() |
||||
|
||||
perm.sort(key=lambda x:x[1]) |
||||
print("The following is the sequence of item numbers,") |
||||
print("in the order they are visited for the Josephus problem:") |
||||
print("".join([str(p[0]) for p in perm])) |
||||
print("") |
||||
|
||||
perm.sort(key=lambda x:x[0]) |
||||
print("The following is the sequence of integers indicating order of visitation") |
||||
print("for each possible position around the circle, listed in clockwise order") |
||||
print("of location around the circle:") |
||||
print("".join([str(p[1]) for p in perm])) |
||||
print("") |
||||
|
||||
|
||||
if __name__=="__main__": |
||||
josephus() |
||||
|
||||
|
Loading…
Reference in new issue