您的位置:首页 > 编程语言 > Python开发

经典递归算法之排列,组合,集合和换零钱, Python yield实现.

2014-08-08 14:51 429 查看
对于每个函数名'f',还有个非递归的版本'xf',例如 perm和xperm, comb和xcomb等.

全部是以生成器的形式实现.例如:perm((1,2,3))返回(1,2,3)的全排列生成器.

def subsets(s):
if not s:
yield ()
else:
head, rest = s[:1], s[1:]
for se in subsets(rest):
yield se
yield head + se

def xsubsets(s):
stk = [(s, ())]
while stk:
s, head = stk.pop()
if not s:
yield head
else:
stk.append((s[1:], head + s[:1]))
stk.append((s[1:], head))

def comb(s,k=None):
n = len(s)
if k is None:
k = n
if k < 0:
raise ValueError("k must be non-negative")
if k > n:
return ()
def recur(s, k, n):
if k == n:
yield s
elif k == 0:
yield ()
else:
head, rest = s[:1], s[1:]
yield from recur(rest, k, n-1)
yield from (head + x for x in recur(rest, k-1, n-1))
return recur(s, k, n)

def xcomb(s,k=None):
n = len(s)
if k is None:
k = n
if k < 0:
raise ValueError("k must be non-negative")
if k > n:
return ()
def recur(s, k, n):
stk = [(s, k, n, ())]
while stk:
s, k, n, head = stk.pop()
if k == n:
yield head + s
elif k == 0:
yield head
else:
stk.append((s[1:], k-1, n-1, head + s[:1]))
stk.append((s[1:], k, n-1, head))
return recur(s, k, n)

def wperm(s):
if not s:
yield ()
else:
head, rest = s[:1], s[1:]
rest_n = len(rest) + 1
for ele in wperm(rest):
for i in range(rest_n):
yield ele[:i] + head + ele[i:]

def xwperm(s):
stk = [(s, ())]
while stk:
s, head = stk.pop()
if not s:
yield head
else:
h = s[:1]
n = len(head) + 1
for i in range(n):
stk.append((s[1:], head[:i] + h + head[i:]))

def perm(s,k=None):
for cs in comb(s,k):
yield from wperm(cs)

def xperm(s,k=None):
for cs in xcomb(s,k):
yield from xwperm(cs)

def exch(my,arr):
if my < 0 or not arr:
pass
elif not arr[1:]:
c = arr[0]
div, mod = divmod(my, c)
if mod == 0:
yield tuple(c for _ in range(div))
else:
head, rest = arr[:1], arr[1:]
yield from exch(my, rest)
yield from (head + x for x in exch(my-arr[0], arr))

def xexch(my,arr):
stk = [(my, arr, ())]
while stk:
my, arr, head = stk.pop()
if my < 0 or not arr:
continue
if not arr[1:]:
c = arr[0]
div, mod = divmod(my, c)
if mod == 0:
yield head + tuple(c for _ in range(div))
else:
stk.append((my-arr[0], arr, head + arr[:1]))
stk.append((my, arr[1:], head))

import itertools

s = tuple(range(5))
arr=tuple(range(1,6000))

def test():
for i in range(len(s)+1):
assert(set(itertools.combinations(s,i))==set(comb(s,i)))

def test2():
for i in range(len(s)+1):
assert(set(itertools.permutations(s,i))==set(perm(s,i)))

def test3():
for x in xexch(10,arr):
print(x)
#assert(set(xexch(10,arr))==set(exch(10,arr)))

def test4():
for i in range(len(s)+1):
assert(set(xcomb(s,i))==set(comb(s,i)))
for x in xcomb(s, 2):
print(x)

def test5():
for ss in subsets(arr):
print(ss)
print('---')
for ss in xsubsets(arr):
print(ss)
assert(set(subsets(arr))==set(xsubsets(arr)))

def test6():
#assert(set(perm(arr,3))==set(xperm(arr,3)))
for x in xperm(arr,3):
print(x)

if __name__=='__main__':

test6()
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: