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

对于每个函数名'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()


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值