【问题标题】:A method to print linked list in reverse/backward order in python在python中以反向/向后顺序打印链表的方法
【发布时间】:2015-12-14 10:50:28
【问题描述】:

我正在编写一个名为 LList 的类,并在该类中定义了几个方法。我在编写一种以反向顺序打印链接列表的方法时遇到问题。

class Node(object):
    def __init__(self, data=None, nextNode=None):
        self.data = data
        self.nextNode = nextNode

class LList(object):

    def __init__(self, head=None):
        self.head = head
        self.size = 0

    def insert(self, node):

        if not self.head:
            self.head = node
            self.size += 1
        else:
            # set new nodes pointer to old head
            node.nextNode = self.head
            # reset head to new node
            self.head = node
            self.size +=1

    def getSize(self):
        return self.size

    def printLL(self):
        mynode = self.head
        c = 0
        while mynode:
            c += 1
            print(mynode.data, c)
            mynode = mynode.nextNode

#a method for class that prints list backwards.       
    def reverse(self):


#main program

    MyList = LList()
    MyList.insert(Node("NJ"))
    MyList.insert(Node("NR"))
    MyList.insert(Node("OH"))

    # Use my print method
    MyList.printLL()
    #print in reverse
    MyList.reverse()

【问题讨论】:

  • 你为什么不先尝试一下,然后给我们看代码?

标签: python linked-list


【解决方案1】:
class Node(object):

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

       def ReversePrint(head):
           if head == None:
              return
           else:
             ReversePrint(head.next)
             print(head.data)

我们举一个链表的例子:1->2->3 遍历代码,函数 ReversePrint 被赋予了一个指向我们的链表头部的链接,即 1。我们看到头部不等于 null,所以我们移动到代码的第二行,这是第一个递归调用到 head.next,即 2。我们再次看到这个新的“头”不等于 null,所以我们进行第二次递归调用,这次传递包含 3 的节点。我们看到这个新的“头”是不等于 null,所以我们对 head.next 进行第三次递归调用,在本例中为 null。所以我们返回,因为我们达到了我们的基本情况。我们现在回到我们的第二个递归调用,我们移动到递归调用之后的代码行,即 print 语句。我们打印 3。由于这个递归调用现在已经完成,我们回到第一个递归调用,并打印 2。最后,我们回到我们的初始函数调用,我们打印 1。因此,成功地反向打印我们的链表命令。

【讨论】:

    【解决方案2】:

    好吧,除非你有一个双链表,否则最好的选择是遍历整个链表,将所有内容保存在内存中,然后打印出来。

    这可能是您的代码草稿:

    def print_reversed(self):
    
        node = self.head
        values = []
        while node:
            values.append(node.data)
            node = node.nextNode
    
        for value in reversed(values):
            print(value)
    

    这在某种程度上违背了链表的目的。您也可以递归地执行此操作,但 IMO 看起来会很混乱。

    【讨论】:

      【解决方案3】:

      我预计您的问题是由于没有有效的方法来向后迭代单链表。

      我通过使用一些魔术方法(又名dunder 方法)稍微增强了您的代码:名称(通常)以双下划线开头和结尾的方法。您可以在Special method names 下的文档中了解它们。

      对象的__str__ 方法在对象被传递给str 内置函数时被调用(当您尝试打印对象时会隐式发生)。如果对象没有__str__ 方法,则调用其__repr__ 方法;通常最好定义这两种方法中的至少一种,否则当您尝试打印对象时,将调用从通用 object 继承的默认 __repr__ 方法。

      我已将您的 getSize 方法更改为 __len__,当将对象传递给 len 内置函数时会调用该方法。

      对象的__iter__ 方法在传递给iter 内置函数时被调用,无论是显式地还是当您尝试在某种for 循环中迭代对象时,或者当您将它传递给list 或类似的构造函数。它通常与__next__ 方法结合使用,该方法(不幸地)在Python 2 中被命名为next。当一个对象具有这些方法时,以各种方式对其进行迭代相对容易。

      要进行反向打印,我们可以简单地将实例传递给list,并将结果列表传递给reversed,它会返回一个迭代器,该迭代器在其列表参数上进行反向迭代。

      下面的代码是为 Python 2 编写的;将 Python 3 的 next 方法更改为 __next__

      class Node(object):
          def __init__(self, data=None, nextNode=None):
              self.data = data
              self.nextNode = nextNode
      
          def __str__(self):
              return str(self.data)
      
      class LList(object):
          def __init__(self):
              self.head = None
              self.current = None
              self.size = 0
      
          def insert(self, node):
              if self.head is not None:
                  # set new node's pointer to old head
                  node.nextNode = self.head
              self.head = node
              self.size += 1
      
          def __len__(self):
              return self.size
      
          def __iter__(self):
              self.current = self.head
              return self
      
          def next(self):
              current = self.current
              if current is None:
                  raise StopIteration
              else:
                  self.current = current.nextNode
                  return current
      
          def printLL(self):
              for i, node in enumerate(self, 1):
                  print(node, i)
      
          # print the list backwards
          def reverse_print(self):
              c = len(self)
              for node in reversed(list(self)):
                  print(node, c)
                  c -= 1
      
      
      # main program
      mylist = LList()
      mylist.insert(Node("NJ"))
      mylist.insert(Node("NR"))
      mylist.insert(Node("OH"))
      
      print(len(mylist))
      
      # print forwards
      mylist.printLL()
      
      #print the nodes using a list comprehension
      print([str(node) for node in mylist])
      
      #print in reverse
      mylist.reverse_print()
      

      输出

      3
      OH 1
      NR 2
      NJ 3
      ['OH', 'NR', 'NJ']
      NJ 3
      NR 2
      OH 1
      

      【讨论】:

      • 收到“self”不可迭代的投诉
      • @Oliver 真的吗?那是 exact 错误信息吗?你使用的是什么版本的 Python? FWIW,代码在 Python 3.6.0 上完美运行,一旦我将 next 方法的名称更改为 __next__,如上所述。如果我尝试在 Python 3.6 上未更改地运行该代码,则会收到以下错误消息:TypeError: iter() returned non-iterator of type 'LList'
      • 使用 Python 3.5.3
      • @Oliver 你把LList.next方法的名字改成__next__了吗?
      【解决方案4】:

      您可以通过使用两个循环来实现它。一种用于循环整个列表,另一种用于相对于主循环进入特定节点并打印它。 Count() 返回节点数。当计数值为 0 时,节点循环由于 (self.Count() - count) 而在最后一个节点处停止并打印它。就这样倒退了。

      def reverse(self):
          for count in range(self.Count()+1):
             
              iteration = 0       
              printval = self.head
      
              while printval != None:
                  if iteration == (self.Count() - count):  
                      break
                  printval = printval.next
                  iteration = iteration + 1
              print(printval.name)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-24
        • 1970-01-01
        • 1970-01-01
        • 2012-04-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-20
        相关资源
        最近更新 更多