Browse Source

add doubly linked list solution assembly

master
Charles Reid 6 years ago
parent
commit
71a12e751f
  1. 213
      josephus.py

213
josephus.py

@ -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…
Cancel
Save