单链表反转 Python 版

1,875 阅读5分钟

前言

链表结构,说难不难,说易不易,一定要亲自编程实现一下。其次就是一定要耐心,慢慢去体会其中的道道,博主一开始也是有点懵逼的,后来仔细琢磨了一下终于搞明白了,相信聪明的你也一定可以,有问题可以留言交流。

单链表结构


反转死链

题目描述

反转单链表。例如链表为:

1->2->3->4

反转后为

4->3->2->1

要求

如果链表的长度为 N, 时间复杂度达到 O(N), 额外空间复杂度达到 O(1)

代码实现

方案一

当我们在反转一个节点的时候,把一个节点的后驱改为指向它前驱就可以了。这里需要注意的点就是,当你把当前节点的后驱指向前驱的时候,这个时候链表会被截断,也就是说后面的节点和当前节点分开了,所以我们需要一个变量来保存当前节点的后驱,以访丢失。

# 思路: 建立三个变量,L、M、R互相赋值迭代,并建立指向关系,从而实现单链表的反转。
#!/bin/env python
#coding: utf-8

class Node(object):
    """
    订阅单个节点结构
    """
    def __init__(self, Data, Next=None):
        self.val  = Data
        self.next = Next

def reverseNode(Node):
    """
    反转列表
    """
    if Node == None:
        return None

    # 单向链表:n0 -> n1 -> n2 -> n3 -> n4
    #
    # 此处关键思路:
    # 1. 优先声明三个变量,用于遍历列表节点中的数据转换
    # 2. 为了实现数据的滚动,故需要将遍历节点(或指针)右移,即:l=m m=r r=r.next
    # 3. 节点滚动过程中,由 m 承接右节点的数据,并链接前面的节点(逆序),r 承接下一个指针的数据,l 承接 m 的中间数据过渡,即:
    #        随着节点滚动,m 值的变化为:
    #           Time 1: n0
    #           Time 2: n1 -> n0
    #           Time 3: n2 -> n1 -> n0
    #           Time 4: n3 ->n2 -> n1 -> n0
    #
    #         # 遍历到最后一个节点时,就无法在 while 循环中了,故需要将获得的 m 值关联到 r 值上,即:r.next = m
    #           Time 5: n4 -> n3 -> n2 -> n1 -> 0
    L, M, R = None, None, Node
    while R.next != None:
        L = M
        M = R
        R = R.next
        M.next = L
    R.next = M

    return R

def output(lists):
    """
    输出链表
    """
    temp = lists
    while temp != None:
        print temp.val
        temp = temp.next

    print '+++++++++++++++++++++\n'

if __name__ == '__main__':
    l1 = Node(1)
    l1.next = Node(2)
    l1.next.next = Node(3)
    l1.next.next.next = Node(4)

    print 'Input list:\n====================='
    output(l1)
    l = reverseNode(l1)
    print '\nOutput list:\n====================='
    output(l)

# --------------------- #

#!/usr/bin/env python
#coding = utf-8
class Node:
    def __init__(self,data=None, next = None):
        self.data = data
        self.next = next

def rev(link):
    pre = link
    cur = link.next
    pre.next = None
    while cur:
        temp = cur.next
        cur.next = pre
        pre =cur
        cur = temp
    return pre

if __name__ == '__main__':
    link = Node(1, Node(2, Node(3, Node(4, Node(5, Node(6, Node(7, Node(8, Node(9)))))))))
    root = rev(link)
    while root:
        print(root.data)
        root =root.next

解释一下rev函数的实现过程:

  • line 9-11是将原链表的第一个节点变成了新链表的最后一个节点,同时将原链表的第二个节点保存在cur中
  • line13-16就是从原链表的第二个节点开始遍历到最后一个节点,将所有节点翻转一遍

以翻转第二个节点为例

  • temp = cur.next是将cur的下一个节点保存在temp中,也就是第节点3,因为翻转后,节点2的下一个节点变成了节点1,原先节点2和节点3之间的连接断开,通过节点2就找不到节点3了,因此需要保存
  • cur.next = pre就是将节点2的下一个节点指向了节点1
  • 然后pre向后移动到原先cur的位置,cur也向后移动一个节点,也就是pre = cur ,cur =temp

这种就为翻转节点3做好了准备

方案二

这道题也可以用递归来做,假设 方法 reverse() 的功能是将单链表进行逆转。采用递归的方法时,我们可以不断着对子链表进行递归。例如对于如下的链表:


我们对子链表 2->3->4 进行递归,即
Node newList = reverse(head.next)。递归之后的结果如下:


逆转之后子链表 2->3->变为了 4->3->2。
注意,我刚才假设 reverse() 的功能就是对链表进行逆转。不过此时节点 1 仍然是指向节点 2 的。这个时候,我们再把节点1 和 2逆转一下,然后 1 的下一个节点指向 null 就可以了。如图:


递归的结束条件就是:当子链表只有一个节点,或者为 null 时,递归结束。代码如下:

//用递归的方法反转链表    
#!/usr/bin/env python
#coding = utf-8
class Node:
    def __init__(self,data=None,next = None):
        self.data = data
        self.next = next


def reverseNode(Node):
    if Node == None or Node.next == Nonereturn Node

    // 递归反转子链链表
    newNode = reverseNode(Node.next);    //第三张图
    Node.next.next = Node;
    Node.next = None;

    return newNode;

if __name__ == '__main__':
    link = Node(1, Node(2, Node(3, Node(4, Node(5, Node(6, Node(7, Node(8, Node(9)))))))))    new  = reverseNode(link)
    print new

问题拓展

题目:反转部分链表节点

题目描述

题目:给定一个单向链表的头结点head,以及两个整数from和to ,在单项链表上把第from个节点和第to个节点这一部分进行反转

列如:
1->2->3->4->5->null,from=2,to=4

结果:1->4->3->2->5->null

列如:

1->2->3->null from=1,to=3

结果为 3->2->1->null

要求

1、如果链表长度为N,时间复杂度要求为O(N),额外空间复杂度要求为O(1)

2、如果不满足1<=from<=to<=N,则不调整