使用递归反转单个链接列表

时间:2018-09-11 22:50:08

标签: python oop recursion linked-list reverse

我制作了一个函数,该函数使用递归方法反转单个链接列表。 但是我在执行下面的代码时遇到了一些困难:

class node:
    def __init__(self,data=None):
        self.next=None
        self.data=data

class linked_list:
    def __init__(self):
        self.head=node()

def append(self,data):
    new_node=node(data)
    cur_node=self.head
    while (cur_node.next!=None):
        cur_node=cur_node.next
    cur_node.next=new_node
    return cur_node.data

def display(self):
    elements=[]
    cur_node=self.head
    while(cur_node.next!=None):
        cur_node=cur_node.next
        elements.append(cur_node.data)
    print(elements)

def reverseRecursive(self,prev_code,cur_node):
    if cur_node.next!=None:
        reverseRecursive(cur_node,cur_node.next)
        cur_node.next=prev_node
    else:
        self.head=cur_node
    return
lst1=linked_list()
lst1.display()
lst1.append(1)
lst1.append(3)
lst1.append(5)
lst1.append(7)
lst1.display()
lst1.reverseRecursive(None,_____)
lst1.display()

我应该如何在reverseRecursive函数/方法中传递第二个参数,以便我可以执行它?

作为第二个论点,我想简单地传递链接列表的 head 节点。但是我不知道如何从 linked_list

类的 init方法获取头节点。

我尝试了几件事,但是无法解决。也许我不太擅长OOP概念。有人可以帮我解决这个问题吗?

1 个答案:

答案 0 :(得分:0)

链表是递归结构,因此将其与功能样式一起使用将产生最佳效果。在您的程序中,您已使用过程样式和mutable节点实现了一个链表–您随时间更改了datanext的值。尽管这听起来像是一种直观的方法,但我想专注于不可变学科,这使我们摆脱了严重的状态复杂性。

首先,我们修复node构造函数。我们在构建新节点时会同时设置这两个属性,因为它们在程序中以后不会更改–

class node:
  def __init__ (self, data, next):
    self.data = data
    self.next = next

然后linked_list只是由特定约定构造的单个节点:

  • node.data保留节点的数据
  • node.next是:
    • 另一个linked_list
    • None,代表列表的结尾

我们从linked_list的构造函数开始–

class linked_list:
  def __init__ (self, node = None):
    self.node = node

  # ...

并实现is_emptyheadtail properties,以抽象出node

class linked_list:
  def __init__ (self, node = None):
    self.node = node

  @property
  def is_empty (self):
    return self.node is None

  @property
  def head (self):
    if self.is_empty:
      raise Exception ("cannot get head of an empty list")
    else:
      return self.node.data

  @property
  def tail (self):
    if self.is_empty:
      raise Exception ("cannot get tail of an empty list")
    else:
      return self.node.next

现在已经完全抽象了node的使用,并且我们可以通过使用我们的新属性来编写更高级别的列表行为–

class linked_list:
  ... 

  def length (self):
    if self.is_empty:
      return 0
    else:
      return 1 + self.tail.length()

上面,我们看到通过使用列表的属性来谈论我们的列表非常容易。在继续之前,让我们看看如何使用print构造列表并使它们可视化。对于对象到字符串的转换,我们使用__str__

class linked_list:
  ... 

  def add (self, x):
    return linked_list (node (x, self))

  def __str__ (self):
    if self.is_empty:
      return "None"
    else:
      return str (self.head) + " -> " + str (self.tail)

ls = linked_list().add('A').add('B').add('C')
print (ls)
# C -> B -> A -> None

print (ls.length())
# 3

请记住,由于我们已经建立了一个不可变的链表,add不会更改其被调用的列表–

ls = linked_list().add('A').add('B').add('C')
print (ls)
# C -> B -> A -> None

print (ls.add('D'))
# D -> C -> B -> A -> None

print (ls)
# C -> B -> A -> None

最后,我们可以实现reverse

class linked_list:

  # ...

  def reverse (self):
    def loop (ls, acc):
      if ls.is_empty:
        return acc
      else:
        return loop (ls.tail, acc.add(ls.head))
    return loop (self, linked_list())

ls = linked_list().add('A').add('B').add('C')
print (ls)
# C -> B -> A -> None

print (ls.reverse())
# A -> B -> C -> None

反转列表不会使其突变

print (ls)
# C -> B -> A -> None

print (ls.reverse())
# A -> B -> C -> None

print (ls)
# C -> B -> A -> None