单链表类 与 循环单链表类 的实现 以及Josephus问题
#!/usr/bin/env python
# -*- coding: utf-8 -*-
class LNode:
def __init__(self, elem, next_ = None):
self.elem = elem
self.next = next_
class LinkedListUnderflow(ValueError):
pass
class LList:
def __init__(self):
self._head = None
def is_empty(self):
return self._head is None
def length(self):
p, n = self._head, 0
while p is not None:
n += 1
p = p.next
return n
# 前端操作
def prepend(self, elem):
self._head = LNode(elem, self._head)
def pop(self):
if self._head is None: # 无节点, 引发异常
raise LinkedListUnderflow("in pop")
e = self._head.elem
self._head = self._head.next
return e
# 后端操作
def append(self, elem):
if self._head is None:
self._head = LNode(elem)
return
p = self._head
while p.next is not None:
p = p.next
p.next = LNode(elem)
def pop_last(self):
if self._head is None:
raise LinkedListUnderflow("in pop_last")
p = self._head
if p.next is None:
e = p.elem
self._head = None
return e
while p.next.next is not None:
p = p.next_
e = p.next.elem
p.next = None
return e
# 其他操作
def find(self, pred): # pred为条件函数
p = self._head
while p is not None:
if pred(p.elem):
return p.elem
p = p.next
def printall(self):
p = self._head
while p is not None:
print(p.elem, end=' ')
if p.next is not None:
print(', ', end=' ')
p = p.next
print(' ')
def for_each(self, proc):
p = self._head
while p is not None:
proc(p.elem)
p = p.next
# 迭代器
def elements(self):
p = self._head
while p is not None:
yield p.elem
p = p.next
'''
for x in list1.elements():
print(x)
'''
# 筛选生成器
def filter(self, pred):
p = self._head
while p is not None:
if pred(p.elem):
yield p.elem
p = p.next
# 链表反转
def rev(self):
p = None
while self._head is not None:
q = self._head
self._head = q.next
q.next = p
p = q
self._head = p
#循环单链表类
class LCList:
def __init__(self):
self._rear = None
def is_empty(self):
return self._rear is None
def prepend(self, elem): # 前端插入
p = LNode(elem)
if self._rear is None:
p.next = p # 建立一个节点的环
self._rear = p
else:
p.next = self._rear.next
self._rear.next = p
def append(self, elem): # 尾端插入
self.prepend(elem)
self._rear = self._rear.next
def pop(self): # 前端弹出
if self._rear is None:
raise LinkedListUnderflow("in pop of CLList")
p = self._rear.next
if self._rear is p:
self._rear = None
else:
self._rear.next = p.next
return p.elem
def printall(self):
if self.is_empty():
return
p = self._rear.next
while True:
print(p.elem)
if p is self._rear:
break
p = p.next
# josephus问题应用
class Josephus(LCList):
'''
josephus问题是数据结构中常见的一个实例:假设有n个人围坐一圈,现在要求从第k个人开始报数,报到第m个数的人退出。然后从下一个人开始
继续报数并按照同样规则退出,直到所有人退出。要求按照顺序输出各出列人的编号。
使用循环单链表,算法分为两个阶段:
1. 建立包含指定个数(和内容)的节点的循环单链表,可以通过从空表出发,在尾部逐个加入元素的方法完成
2. 循环计数, 找到并删除应该退出的节点
时间复杂度O(m x n)
'''
def turn(self, m):
for i in range(m):
self._rear = self._rear.next
def __init__(self, n, k, m):
LCList.__init__(self)
for i in range(n):
self.append(i + 1)
self.trun(k - 1)
while not self.is_empty():
self.trun(m - 1)
print(self.pop(), end=("\n" if self.is_empty() else ", "))