【问题标题】:Reversing a linked list in python在python中反转链表
【发布时间】:2014-02-27 01:22:19
【问题描述】:

我被要求反转以 head 作为参数的 a,其中 head 是一个链表,例如:1 -> 2 -> 3,它是从已经定义的函数返回的,我试图以这种方式实现函数 reverse_linked_list:

def reverse_linked_list(head):
    temp = head
    head = None
    temp1 = temp.next
    temp2 = temp1.next
    temp1.next = None
    temp2.next = temp1
    temp1.next = temp
    return temp2

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

    def to_linked_list(plist):
    head = None
    prev = None
    for element in plist:
        node = Node(element)
        if not head:
            head = node
        else:
            prev.next = node
        prev = node
    return head

    def from_linked_list(head):
    result = []
    counter = 0
    while head and counter < 100: # tests don't use more than 100 nodes, so bail if you loop 100 times.
        result.append(head.value)
        head = head.next
        counter += 1
    return result

    def check_reversal(input):
        head = to_linked_list(input)
        result = reverse_linked_list(head)
        assert list(reversed(input)) == from_linked_list(result)

这样调用:check_reversal([1,2,3])。我为反转列表而编写的函数给出了[3,2,1,2,1,2,1,2,1],并且仅适用于长度为 3 的列表。如何将其概括为长度为 n 的列表?

【问题讨论】:

  • 我没见过python中链表的实际用法,太低级了。这是一个很好的解释,为什么你不会使用它。 stackoverflow.com/questions/280243/python-linked-list#280284
  • 好吧,这可能不太好,但 OP 被 要求 去做(家庭作业?):P
  • @Ramya 答案取决于你想怎么做。我们不知道您是否可以在reverse_linked_list 中使用 Python 列表。如果是后者,那么我们需要知道您正在使用的 listutils...
  • @Ricardo cardenes我不能使用列表,但是,我的 listutils 函数将列表 ex:[1,2,3] 转换为链表。所以我应该将尾节点作为头节点
  • @Ramya 我的意思是:如果您使用我们不知道的库,我们无法帮助您。我们可以编写伪代码向您展示如何操作,但这在 Internet 和教科书中随处可见,如果这是家庭作业(并且看起来 100% 喜欢它),您应该至少展示一段代码,您首先尝试这样做,然后我们可能会更正它 - 作为一般规则,这就是您应该在 StackOverflow 中提问的方式。

标签: python linked-list


【解决方案1】:

您可以执行以下操作来反转单链表(我假设您的列表是单链的)。

首先你创建一个类节点,并启动一个默认构造函数,它将获取其中的数据值。

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

此解决方案将“迭代地”反转您的链表。 我正在创建一个名为 SinglyLinkedList 的类,它将有一个构造函数:

class SinglyLinkedList:
    def __init__(self):
        self.head = None
    

然后我写了一个方法来反转列表,打印列表的长度,并打印列表本身:

# method to REVERSE THE LINKED LIST
def reverse_list_iterative(self):
    prev = None
    current = self.head
    following = current.next
    while (current):
        current.next = prev
        prev = current
        current = following
        if following:
            following = following.next
    self.head = prev

        
# Method to return the length of the list
def listLength(self):
    count = 0
    temp = self.head
    while (temp != None):
        temp = temp.next
        count += 1
    return count

# Method to print the list
def printList(self):
    if self.head ==  None:
        print("The list is empty")
    else:
        current_node = self.head
        while current_node:
            print(current_node.data, end = " -> ")
            current_node = current_node.next
        
        if current_node == None:
            print("End")`

然后我对列表及其内容进行硬编码,然后链接它们

if __name__ == '__main__':
    sll = SinglyLinkedList()
    sll.head = Node(1)
    second = Node(2)
    third = Node(3)
    fourth = Node(4)
    fifth = Node(5)

    # Now linking the SLL
    sll.head.next = second
    second.next = third
    third.next = fourth
    fourth.next = fifth

    print("Length of the Singly Linked List is: ", sll.listLength())
    print()
    print("Linked List before reversal")
    sll.printList()
    print()
    print()
    sll.reverse_list_iterative()
    print("Linked List after reversal")
    sll.printList()

输出将是:

单链表的长度为:5

反转前的链表1 -&gt; 2 -&gt; 3 -&gt; 4 -&gt; 5 -&gt; End

反转后的链表 5 -&gt; 4 -&gt; 3 -&gt; 2 -&gt; 1 -&gt; End

【讨论】:

    【解决方案2】:

    以下是反转单链表的通用代码,其中 head 作为函数的参数给出:

    def reverseSll(ll_head):
        # if head of the linked list is empty then nothing to reverse
        if not ll_head:
            return False
        # if only one node, reverse of one node list is the same node
        if not ll_head.next:
            return ll_head
        else:
            second = ll_head.next # get the second node of the list
            ll_head.next = None # detach head node from the rest of the list
            reversedLL = reverseSll(second) # reverse rest of the list
            second.next = ll_head # attach head node to last of the reversed list
            return reversedLL
    

    让我解释一下我在这里做什么:

    1)如果head为null或head.next为null(列表中只剩下一个节点)返回节点
    2) else 部分:取出第一个节点,删除其与列表其余部分的链接,反转列表的其余部分(reverseSll(second)),最后再次添加第一个节点并返回列表

    Github link for the same

    【讨论】:

      【解决方案3】:

      我发现 blckknght 的答案很有用,而且肯定是正确的,但我很难理解实际发生的情况,主要是因为 Python 的语法允许在一行上交换两个变量。我还发现变量名称有点混乱。

      在这个例子中,我使用previous, current, tmp

      def reverse(head):
          current = head
          previous = None
      
          while current:
              tmp = current.next
              current.next = previous   # None, first time round.
              previous = current        # Used in the next iteration.
              current = tmp             # Move to next node.
      
          head = previous
      

      以一个有 3 个节点的单链表(head = n1,tail = n3)为例。

      n1 -&gt; n2 -&gt; n3

      在第一次进入while循环之前,previous被初始化为None,因为头部之前没有节点(n1)。

      我发现想象变量previous, current, tmp'沿着'链表移动很有用,总是按那个顺序。

      第一次迭代

      previous = None

      [n1] -> [n2] -> [n3] current tmp current.next = previous

      第二次迭代

      [n1] -> [n2] -> [n3] previous current tmp current.next = previous

      第三次迭代

      # next is None
      

      [n1] -> [n2] -> [n3] previous current current.next = previous

      由于while 循环在current == None 时退出,列表的新头必须设置为previous,这是我们访问的最后一个节点。

      已编辑

      在 Python 中添加一个完整的工作示例(使用 cmets 和有用的str 表示)。我使用tmp 而不是next 因为next 是一个关键字。但是我碰巧认为这是一个更好的名称,并且使算法更清晰。

      class Node:
          def __init__(self, value):
              self.value = value
              self.next = None
      
          def __str__(self):
              return str(self.value)
      
          def set_next(self, value):
              self.next = Node(value)
              return self.next
      
      
      class LinkedList:
          def __init__(self, head=None):
              self.head = head
      
          def __str__(self):
              values = []
              current = self.head
              while current:
                  values.append(str(current))
                  current = current.next
      
              return ' -> '.join(values)
      
          def reverse(self):
              previous = None
              current = self.head
      
              while current.next:
                  # Remember `next`, we'll need it later.
                  tmp = current.next
                  # Reverse the direction of two items.
                  current.next = previous
                  # Move along the list.
                  previous = current
                  current = tmp
      
              # The loop exited ahead of the last item because it has no
              # `next` node. Fix that here.
              current.next = previous
      
              # Don't forget to update the `LinkedList`.
              self.head = current
      
      
      if __name__ == "__main__":
      
          head = Node('a')
          head.set_next('b').set_next('c').set_next('d').set_next('e')
      
          ll = LinkedList(head)
          print(ll)
          ll.revevse()
          print(ll)
      

      结果

      a -> b -> c -> d -> e
      e -> d -> c -> b -> a
      

      【讨论】:

        【解决方案4】:

        以前的大多数答案都是正确的,但没有一个包含完整的代码,包括在反向之前和之后的 insert 方法,因此您可以实际查看输出并进行比较。这就是为什么我要回答这个问题。代码的主要部分当然是 reverse_list() 方法。 顺便说一下,这是在 Python 3.7 中。

        class Node(object):
            def __incurrent__(self, data=None, next=None):
                self.data = data
                self.next = next
        
        
        class LinkedList(object):
        
            def __incurrent__(self, head=None):
                self.head = head
        
            def insert(self, data):
                tmp = self.head
                self.head = Node(data)
                self.head.next = tmp
        
            def reverse_list(self):
                current = self.head
                prev = None
        
                while current :
                    #create tmp to point to next
                    tmp = current.next
                    # set the next to point to previous
                    current.next = prev
                    # set the previous to point to current
                    prev = current
                    #set the current to point to tmp
                    current = tmp
                self.head = prev
        
        
            def print(self):
                current = self.head
                while current != None:
                    print(current.data,end="-")
                    current = current.next
                print(" ")
        
        
        lk = LinkedList()
        lk.insert("a")
        lk.insert("b")
        lk.insert("c")
        
        lk.print()
        lk.reverse_list()
        lk.print()
        

        输出:

        c-b-a- 
        a-b-c- 
        

        【讨论】:

          【解决方案5】:
          def reverseLinkedList(head):
          
              current =  head
              previous = None
              nextNode = None
          
              while current:
          
                  nextNode = current.nextNode
                  current.nextNode = previous
          
                  previous = current
                  current = nextNode
          
              return previous
          

          【讨论】:

          • 虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
          【解决方案6】:

          这是一张纸上的全部内容。包含链表的创建和反转它的代码。

          包含一个示例,因此您可以复制并粘贴到空闲的 .py 文件中并运行它。

          class Node(object):
              def __init__(self, value, next=None): 
                  self.value = value                
                  self.next = next                  
          
          
          def reverse(head):
              temp = head
              llSize = 0
              while temp is not None:
                  llSize += 1
                  temp = temp.next
              for i in xrange(llSize-1,0,-1):
                  xcount = 0
                  temp = head
                  while (xcount != i):
                      temp.value, temp.next.value = temp.next.value, temp.value
                      temp = temp.next
                      xcount += 1
              return head
          
          
          def printnodes(n):
              b = True
              while b == True:
                  try:
                      print n.value
                      n = n.next
                  except:
                      b = False
          
          n0 = Node(1,Node(2,Node(3,Node(4,Node(5,)))))
          print 'Nodes in order...'
          printnodes(n0)
          print '---'
          print 'Nodes reversed...'
          n1 = reverse(n0)
          printnodes(n1)
          

          【讨论】:

            【解决方案7】:

            这是一种“就地”反转列表的方法。这在恒定时间 O(n) 中运行并使用零额外空间。

            def reverse(head):
              if not head:
                return head
              h = head
              q = None
              p = h.next
              while (p):
                h.next = q
                q = h
                h = p
                p = h.next
              h.next = q
              return h
            

            这是一个显示算法运行的动画。
            (# 表示 Null/None 用于动画目的)

            【讨论】:

              【解决方案8】:

              我尝试了一种不同的方法,即反转 LList。 给定一个列表 1,2,3,4

              如果你连续交换附近的节点,你就会得到解决方案。

              len=3 (size-1)
              2,1,3,4
              2,3,1,4
              2,3,4,1
              
              len=2 (size-2)
              3,2,4,1
              3,4,2,1
              
              len=1 (size-3)
              4,3,2,1
              

              下面的代码就是这样做的。外部 for 循环依次减小列表的 len 以进行交换。 While 循环交换节点的数据元素。

              def Reverse(head):
                  temp = head
                  llSize = 0
                  while temp is not None:
                      llSize += 1
                      temp = temp.next
              
              
                  for i in xrange(llSize-1,0,-1):
                      xcount = 0
                      temp = head
                      while (xcount != i):
                          temp.data, temp.next.data = temp.next.data, temp.data
                          temp = temp.next
                          xcount += 1
                  return head
              

              这可能不如其他解决方案有效,但有助于从不同的角度看待问题。希望您觉得这个有帮助。

              【讨论】:

                【解决方案9】:

                接受的答案对我来说没有任何意义,因为它指的是一堆似乎不存在的东西(numbernodelen 作为数字而不是函数) .由于这可能是很久以前的家庭作业,我将发布我认为最有效的代码。

                这是为了进行破坏性反转,您可以在其中修改现有的列表节点:

                def reverse_list(head):
                    new_head = None
                    while head:
                        head.next, head, new_head = new_head, head.next, head # look Ma, no temp vars!
                    return new_head
                

                一个不太花哨的函数实现会使用一个临时变量和几个赋值语句,这可能更容易理解:

                def reverse_list(head):
                    new_head = None  # this is where we build the reversed list (reusing the existing nodes)
                    while head:
                        temp = head  # temp is a reference to a node we're moving from one list to the other
                        head = temp.next  # the first two assignments pop the node off the front of the list
                        temp.next = new_head  # the next two make it the new head of the reversed list
                        new_head = temp
                    return new_head
                

                另一种设计是创建一个全新的列表而不更改旧列表。如果您想将列表节点视为不可变对象,这将更合适:

                class Node(object):
                    def __init__(self, value, next=None): # if we're considering Nodes to be immutable
                        self.value = value                # we need to set all their attributes up
                        self.next = next                  # front, since we can't change them later
                
                def reverse_list_nondestructive(head):
                    new_head = None
                    while head:
                        new_head = Node(head.value, new_head)
                        head = head.next
                    return new_head
                

                【讨论】:

                • 你能添加你的节点实现吗?使用问题中定义的 Node 类时,这两个函数都会出现语法错误。
                • @radtek:嗯,我使用了问题中的实现,尽管缩进是固定的。据我所知,我的两个函数都不应该包含任何语法错误。如果您遇到真正的问题,请提出一个新问题!
                • 节点对象 init 不采用 2 个值,因此失败: Node(head.value, new_head) ,然后另一个我收到 NoneType 错误,没有下一个。我这样创建列表:head = Node(1); head.next = 节点(2); head.next.next = 节点(3)。
                • 哦,我明白了。是的,如果您将Node 对象视为不可变对象(就像我在第二个函数中所做的那样),那么您应该让Node.__init__ 接受第二个参数,并将其保存为self.next(因为,据说,您可以'稍后更改)。我不明白为什么你会在第一个版本中得到错误。如果headNone,则while 循环应该在head.next 被访问之前结束。
                • 是的,在 GCC 4.2.1 Compatible Apple OS X Mavericks 上使用 python 2.7.5 控制台。 h = Node(1); head.next = Node(2); head.next.next = Node(3) 然后 reverse_list(h) 并得到 AttributeError: 'NoneType' object has no attribute 'next'
                【解决方案10】:

                Node 类部分借鉴自交互式 python.org:http://interactivepython.org/runestone/static/pythonds/BasicDS/ImplementinganUnorderedListLinkedLists.html

                我创建了反向函数。 反向循环中的所有 cmets 意味着第一次循环。然后继续。

                class Node():
                  def __init__(self,initdata):
                    self.d = initdata
                    self.next = None
                
                  def setData(self,newdata):
                    self.d = newdata
                
                  def setNext(self,newnext):
                    self.next = newnext
                
                  def getData(self):
                    return self.d
                
                  def getNext(self):
                    return self.next
                
                class LinkList():
                  def __init__(self):
                    self.head = None
                
                  def reverse(self):
                    current = self.head   >>> set current to head(start of node)
                    previous = None       >>>  no node at previous
                    while current !=None: >>> While current node is not null, loop
                        nextt =  current.getNext()  >>> create a pointing var to next node(will use later)
                        current.setNext(previous)   >>> current node(or head node for first time loop) is set to previous(ie NULL), now we are breaking the link of the first node to second node, this is where nextt helps(coz we have pointer to next node for looping)
                        previous = current  >>> just move previous(which was pointing to NULL to current node)
                        current = nextt     >>> just move current(which was pointing to head to next node)
                
                    self.head = previous   >>> after looping is done, (move the head to not current coz current has moved to next), move the head to previous which is the last node.
                

                【讨论】:

                  【解决方案11】:

                  U 可以使用 mod 函数来获取每次迭代的余数,显然这将有助于反转列表。我想你是Mission R和D的学生

                  head=None   
                  prev=None
                  for i in range(len):
                      node=Node(number%10)
                      if not head:
                          head=node
                      else:
                          prev.next=node
                      prev=node
                      number=number/10
                  return head
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-01-30
                    • 2016-03-19
                    • 1970-01-01
                    相关资源
                    最近更新 更多