具有多个链表作为参数的递归替代/合并链表功能?

时间:2019-02-26 07:37:27

标签: python recursion linked-list

我在使用带有多个链表参数的递归链表功能时遇到麻烦。

到目前为止,我已经在下面提出了一个链接列表,并且效果很好。

def recursive_ll(ll):
    if ll == None:
        return None
    elif ll.next == None:
        return LN(ll.value)
    else:
        return_ll = LN(ll.value, recursive_ll(ll.next))
        if return_ll.value == return_ll.next.value:
            return_ll = return_ll.next
    return return_ll 

结果将是:

ll = list_to_ll(['x','g','f','n'])
print(str_ll(recursive_ll(ll)))

x->g->f->n->None

但是我真的对如何创建以多个链表作为参数的递归链表函数感到困惑。

例如,def recursive_ll(ll):将是def recursive_ll(ll,ll2):

返回的结果将是

ll = recursive_ll(['a','x','b','e'])
ll2 = recursive_ll(['d','f','m'])

a->d->x->f->b->m->e->None

再次从两个链接列表中合并以下所需的结果:

a->d->x->f->b->m->e->None

任何帮助/建议将不胜感激!

2 个答案:

答案 0 :(得分:1)

您应该使用类而不是简单的函数作为助手。并接受任何可迭代项作为链表的来源。如果在链接列表类上实现迭代器,则将允许在任何可迭代列表和链接列表之间进行微不足道的转换。

链接列表类可以是:

class LL:
    class iter:
        def __init__(self, ll):
            self.cur = ll.front
        def __iter__(self):
            return self
        def __next__(self):
            if self.cur is None:
                raise StopIteration()
            val = self.cur.value
            self.cur = self.cur.next
            return val

    def __init__(self, l):
        self.front = last = None
        for v in l:
            ln = LN(v)
            if last is None:
                self.front = ln
            else:
                last.next = ln
            last = ln

    def __str__(self):
        answer = ''
        for val in self.iter_elt():
            answer += str(val) + '->'
        return answer + 'None'

    def __repr__(self):
        return str(self.__class__) + ':' + str(self)

    def __iter__(self):
        return LL.iter(self)

这立即允许:

>>> print(LL('abcd'))
a->b->c->d->None
>>> list(LL('abcd'))
['a', 'b', 'c', 'd']

完成此操作后,您可以将“递归链接列表”声明为“链接列表”的子类,如果包含“链接列表”,则可以按合并顺序提取元素。

您应该首先在iter_elt类中添加一个仅调用LL的新方法iter,然后在__str__中使用该方法来简化子类化:

class LL:
    ...
    def __str__(self):
        answer = ''
        for val in self.iter_elt():
            answer += str(val) + '->'
        return answer + 'None'
    ...
    def iter_elt(self):
        return self.__iter__()

因为现在,在RLL中重写iter_elt就足够了,并构建一个迭代器,如果可能的话,它将反复扫描其子列表,反复调用iter_elt,直到其他所有元素都用尽。代码可能是:

class RLL(LL):
    class iter:
        def __init__(self, rll):
            self.iters = LL(i.iter_elt() if hasattr(i, 'iter_elt') else iter(i)
                            for i in rll)
            self.cur = self.iters.front
            self.prev = None
        def __iter__(self):
            return self
        def __next__(self):
            try:
                elt = next(self.cur.value)
                self.prev = self.cur
                self.cur = self.cur.next
                if self.cur is None:
                    self.cur = self.iters.front
                    self.prev = None
            except StopIteration:
                self.cur = self.cur.next
                if self.cur is None:
                    if self.prev is None:
                        raise
                    self.cur = self.iters.front
                    self.prev = None
                else:
                    if self.prev is None:
                        self.iters.front = self.cur
                    else:
                        self.prev.next = self.cur
                elt = self.__next__()
            return elt

    def iter_elt(self):
        return RLL.iter(self)

答案 1 :(得分:1)

我完全同意@Serge Ballesta的观点,即您应该创建一个LinkedList类来执行此操作,这是按照您的操作方式进行操作的方法。

还请注意,它不是递归完成的,而是“ Python式的”。

from itertools import chain, zip_longest

class LN:
    def __init__(self, value, next=None):
        self.value = value
        self.next  = next

def list_to_ll(l):
    if l == []:
        return None
    front = rear = LN(l[0])
    for v in l[1:]:
        rear.next = LN(v)
        rear = rear.next
    return front

def iterate(ll):
    while ll is not None:
        yield ll.value
        ll = ll.next

def str_ll(ll):
    return '->'.join(str(v) for v in iterate(ll)) + '->None'

def alternate(ll_1, ll_2):
    _NULL = object()
    chained = chain.from_iterable(zip_longest(iterate(ll_1), iterate(ll_2), 
                                              fillvalue=_NULL))
    return list_to_ll(list(v for v in chained if v is not _NULL))

if __name__ == '__main__':

    ll_1 = list_to_ll(['a','x','b','e'])
    ll_2 = list_to_ll(['d','f','m'])

    print(str_ll(alternate(ll_1, ll_2)))  # -> a->d->x->f->b->m->e->None