python单链表逆序_单链表逆序

代码有解释,可能一开始看不到,更着动手多敲几遍就能掌握了。加油。

题目描述:

给定一个带头结点的单链表,请将其逆序。即如果单链表原来为head->1->2->3->4->5->6->7,那么逆序后变为head->7->6->5->4->3->2->1。由于单链表与数组不同, 中每个结点的地址都存储在其前驱结点的指针域中, 因此,对单链表中任何 个结点的访问只能从链表的头指针开始进行遍历。在对链表的操作 过程中,需要特别注意在修改结点指针域的时候,记录下后继结点的地址,否 会丢失后继结点。

先定义好链表结构

# -*- coding: utf-8 -*-

"""@author = xuanyun@date = 2019-12-19"""

# 链表数据结构定义

class ListNode:

def __init__(self, x):

self.data = x

self.next = None

class ListOperation:

def __int__(self,node=None):

self.head=node

# 根据链表数据初始化链表

def init_list(self,n_list):

# 初始化一个头指针

head = ListNode("head")

cur = head

for i in n_list:

node = ListNode(i)

cur.next = node

cur = node # 相当于 cur = cur.next,后移

return head

# 遍历链表

def ergodic_list(self,head):

cur = head.next

while cur:

print(cur.data)

cur = cur.next

一、递归逆序

思路:

1、首先将1 -> 2 -> 3 ->4变成1 -> 4-> 3 -> 2(其中2 -> 3 ->4变成4-> 3 -> 2,采用递归方式实现)

2、再将head头节点1移到尾巴,作为尾结点,由于上一个尾结点2,是原先的head.next,此时将2的next指针指向头节点,即head.next.next = head,然后尾结点指向空,即head.next = None

3、特殊情况:头节点为空或者只有1个节点

"""方法功能:对不带头结点的单链表进行逆序输入参数: firstRef:链表头第一个结点"""

def reverse_list_one(firstRef):

#如果链表为空或者链表中只有一个元素

if firstRef is None or firstRef.next is None:

return firstRef

else:

#反转后面的结点

newhead=reverse_list_one(firstRef.next)

#把当前遍历的结点加到后面结点逆序后链表的尾部

firstRef.next.next=firstRef

firstRef.next=None

return newhead

"""方法功能 对带头结点的单链表进行逆序输入参数 head 链表头结点"""

def reverse_have_head(head):

if head is None:

return

#获取链表第一个结点

firstNode=head.next

#对链表进行逆序

newhead=reverse_list_one(firstNode)

#头结点指向逆序后链表的第一个结点

head.next=newhead

return head

算法性能分析:

由于递归法也只需要对链表进行 次遍历,因此,算法的时间复杂度也为 O(N) ,其中,N为链表的长度。递归法的主要优点是:思路比较直观,容易理解,而且也不需要保存前驱 结点的地址

缺点是:算法实现的难度较大,此外,由于递归法需要不断地调用自己,需要 额外的压技与弹枝操作,因此, 与方法 相比性能会有所 降。

二、就地逆序

移动:第1次指针操作,将当前节点指针cur.next值临时保存到nex,即nex = cur.next, 第2次指针操作,将当前的指针cur.next指向其前一个节点pre, 即cur.next = pre,这样就实现了对单个节点的操作。

操作节点的变量移动,pre结点后移:pre_node = cur_node ,cur指向下一个操作节点,即cur = nex,这样通过while循环即可实现对每个节点操作。

特殊情况:链表为空链表、链表为单节点,直接返回即可,无需逆序操作

"""Method Two :就地逆转核心思想:遍历链表,每次遍历都让当前结点指向前驱结点。时间复杂度:O(N)空间复杂度:O(1)"""

def reverse_list_two(head):

""":type head: ListNode:rtype: ListNode"""

if not head.next: # 空链表或者遍历到最后一个结点

return head # 返回头结点

# 第一步:首结点变成逆转后尾结点

cur_node = head.next # 链表首结点

next_node = cur_node.next # 原链表第二个结点

cur_node.next = None # 断开原链表首结点与第二个结点链接

# 第二步:依次逆转后续结点

pre_node = cur_node # 记录前驱结点

cur_node = next_node # 后移一位

while cur_node.next:

next_node = cur_node.next # 记录后继结点

# 让当前结点指向前驱结点

cur_node.next = pre_node # 逆转

pre_node = cur_node # 前驱结点后移

cur_node = next_node # 链表后移,遍历

"""注:为什么这个地方当前结点后移不用cur_node = cur_node.next因为在前面的代码中,cur_node.next = pre_node,即cur_node 的后继结点已经改变所以用next_node来标记逆转前的cur_node的后继结点"""

# 第三步:头结点指向原链表尾结点,完成逆转

cur_node.next = pre_node # 此时的cur_node应该为:原链表尾结点,最后一次逆转

head.next = cur_node # 头结点指向尾结点,完成逆转

return head # 返回头结点

三、插入逆序

直假定原链表为head->1->2->3->4->5->6->7,在遍历到2的时候,将其插入到头结点后,链表变为head->2->1->3->4->5->6->7,同理将后序遍历到的所有结点都插入到头结点head后,就可以实现链表的逆序。实现代码如下:

"""Method Three :插入逆转核心思想:遍历链表,把遍历到的当前结点插入到头结点之后这种方法应该是最好理解的。时间复杂度:O(N)空间复杂度:O(1)"""

def reverse_list_three(head):

""":type head: ListNode:rtype: ListNode"""

if not head.next: # 空链表或者遍历到最后一个结点

return head # 返回头结点

# 第一步:设置尾结点

cur_node = head.next.next # 取出第二个结点

head.next.next = None # 令第一个结点指向None,即设置成尾结点

# 第二步:向后遍历,并把遍历到的结点插入到头结点后

while cur_node:

next_node=cur_node.next # 记录后继结点

cur_node.next=head.next #当前要逆序的节点后面接上已经逆序好的链表head

head.next=cur_node #当前节点变成头节点head

cur_node=next_node # 链表后移

return head # 返回头结点

测试

# 当然,也许还有别的方法,比如建一个辅助的链表

# 欢迎你说出你的想法

# 程序入口,测试函数功能

if __name__ == "__main__":

s = ListOperation() # 初始化一个链表基本操作对象实例

list_data = [1, 2, 3, 4] # 链表初始化数据

head = s.init_list(list_data) # 初始化链表,带头结点

s.ergodic_list(head) # 未逆转前,遍历打印链表

#head = reverse_have_head(head) # 测试方法一,逆转链表

#head = reverse_list_two(head) # 测试方法二,逆转链表

head = reverse_list_three(head) # 测试方法三,逆转链表

print("---------------------")

s.ergodic_list(head) # 逆转后,遍历打印链表

参考:

《python程序员宝典》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值