在python中反转链表

时间:2014-02-03 14:02:26

标签: python linked-list

我被要求反转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
pass

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的列表进行推广?

11 个答案:

答案 0 :(得分:40)

接受的答案对我没有任何意义,因为它指的是一堆似乎不存在的东西(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

答案 1 :(得分:21)

我发现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 -> n2 -> n3

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

我发现想象变量previous, current, tmp&#39;移动&#39;链表,总是按顺序排列。

第一次迭代

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中添加完整的工作示例(带有注释和有用的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

答案 2 :(得分:4)

这是一种方法来反转列表&#39;到位&#39;。它以恒定时间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)

enter image description here

答案 3 :(得分:1)

来自交互式python.org的节点类部分:http://interactivepython.org/runestone/static/pythonds/BasicDS/ImplementinganUnorderedListLinkedLists.html

我创建了反转功能。 反向循环中的所有注释都意味着第一次循环。然后它继续。

false

答案 4 :(得分:0)

我尝试了一种不同的方法,实现了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

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

答案 5 :(得分:0)

这是一张纸上的全部内容。包含链接列表的创建,以及反转它的代码。

包含一个示例,这样您就可以复制并粘贴到空闲的.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)

答案 6 :(得分:0)

def reverseLinkedList(head):

    current =  head
    previous = None
    nextNode = None

    while current:

        nextNode = current.nextNode
        current.nextNode = previous

        previous = current
        current = nextNode

    return previous

答案 7 :(得分:0)

大多数以前的答案是正确的,但是没有一个完整的代码,包括反向之前和之后的 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- 

答案 8 :(得分:0)

以下是用于反转单链列表的通用代码,其中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(列表中仅剩一个节点),则返回node
2)其他部分:取出第一个节点,删除其到列表其余部分的链接,反向列表的其余部分(reverseSll(second)),最后再次添加第一个节点,然后返回列表

Github link for the same

答案 9 :(得分:0)

您可以执行以下操作来反向链接单链列表(我假设您的列表彼此单联)。

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

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 -> 2 -> 3 -> 4 -> 5 -> End反转之前的链接列表

反向链接列表 5 -> 4 -> 3 -> 2 -> 1 -> End

enter image description here

答案 10 :(得分:-6)

你可以使用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