“”“
给定一个带头结点的单链表,请将其逆序。即如果单链表原来为 head -> 1 -> 2 -> 3 ->4 -> 5 -> 6 -> 7,那么逆序后变为head -> 7 -> 6 -> 5 ->4 -> 3 -> 2 -> 1。
”“”
方法一:就地逆序
class LNode:
def __init__(self,data):
self.data = data
self.next = None
def reverse(head):
# 特殊情况:头节点为空或者为单节点,直接返回
if head is None or head.next is None:
return head
pre = None
cur = None
next = None
# 把链表首结点变为尾结点
cur = head.next
next = cur.next
cur.next = None
pre = cur
cur = next
# 使当前遍历到的结点 cur 指向其前驱结点
while cur.next !=None:
next = cur.next
cur.next= pre
pre= cur
cur = cur.next
cur= next
# 链表中最后一个节点指到倒数第二个节点
cur.next = pre
# 将链表的头节点知道原链表的尾节点
head.next = cur
if __name__ == "__main__":
i = 1
#链表的头结点
head = LNode(0)
cur = head
#构造单链表
while i<8:
tmp = LNode(i)
cur.next = tmp
cur = tmp
i += 1
print("原链表:",end=" ")
cur = head.next
while cur != None:
print(cur.data,end=" ")
cur= cur.next
print("\n逆序后:",end=" ")
reverse(head)
cur = head.next
while cur != None:
print(cur.data,end=" ")
cur = cur.next
原链表: 1 2 3 4 5 6 7
逆序后: 7 6 5 4 3 2 1
以上这种方法只需要对链表进行一次遍历,因此,时间复杂度为 O(N) ,其中, N 为链表
的长度。但是需要常数个额外的变量来保存当前结点的前驱结点与后继结点,因此,空间复
杂度为 0(1 )。
方法二:递归法
“”"
假定原链表为1->2->3->4->5->6->7,递归法的主要思路为:先逆序除第一个结点以外
的子链表(将 1->2->3->4->5->6->7 变为 1 ->7->6 ->5 ->4 ->3 ->2 ),接着把结点 1 添加到逆序的子链表的后面( 1 ->7->6->5->4->3->2 变为 7->6->5->4->3->2->1) 。 同理,在逆序链表 2->3->4->5->6->7 时,也是先逆序子链表 3->4->5->6->7 (逆序为 2->7->6->5->4->3),接着实现链表的整体逆序( 2->7->6 ->5 ->4->3 转换为 7->6->5 ->4 ->3->2 ) 。
“”"
class LNode:
def __init__(self, data):
self.data = data
self.next = None
def recursiveReverse(head):
"""
方法功能:对不带头结点的单链表进行逆序
输入参数: firstRef:链表头结点
"""
# 如果链表为空或者链表中只有一个元素
if head is None or head.next is None:
return head
else:
# 反转后面的结点
newhead = recursiveReverse(head.next)
# 把当前遍历的结点加到后面结点逆序后链表的尾部
head.next.next = head
head.next = None
return newhead
def reverse(head):
"""
方法功能 : 对带头结点的单链表进行逆序
输入参数 : head ·链表头结点
"""
if head is None:
return
# 获取链表第一个结点
firstNode = head.next
# 对链表进行逆序
newhead = recursiveReverse(firstNode)
# 头结点指向逆序后链表的第一个结点
head.next = newhead
return newhead
if __name__ == "__main__":
i = 1
# 链表的头结点
head = LNode(0)
cur = head
# 构造单链表
while i < 8:
tmp = LNode(i)
cur.next = tmp
cur = tmp
i += 1
print("原链表:", end=" ")
cur = head.next
while cur != None:
print(cur.data, end=" ")
cur = cur.next
print("\n逆序后:", end=" ")
reverse(head)
cur = head.next
while cur != None:
print(cur.data, end=" ")
cur = cur.next
原链表: 1 2 3 4 5 6 7
逆序后: 7 6 5 4 3 2 1
由于递归法也只需要对链表进行一次遍历,因此,算法的时间复杂度也为 O(N),其中,
N 为链表的长度。递归法的主要优点是:思路比较直观,容易理解,而且也不需要保存前驱
结点的地址。缺点是:算法实现的难度较大,此外,由于递归法需要不断地调用自己,需要
额外的压技与弹枝操作,因此, 与方法一相比性能会有所下降。
方法三:插入法
“”"
插入法的主要思路为:从链表的第二个结点开始,把遍历到的结点插入到头结点的后面 ,直到遍历结束。假定原链表为 head -> l ->2 ->3 ->4->5 ->6 ->7 , 在遍历到 2 的时候,将其插入到头结点后,链表变为 head->2-> l ->3->4 ->5->6->7,同理将后序遍历到的所有结点都插入到头结点 head 后,就可以实现链表的逆序。
“”"
class LNode:
def __init__(self, data):
self.data = data
self.next = None
def reverse(head):
# 判断链表是否为空
if head is None or head.next is None:
return
cur = None
next = None
cur = head.next.next
# 设置链表第一个结点为尾结点
head.next.next = None
# 把遍历到结点插入到头结点的后面
while cur is not None:
next = cur.next
cur.next = head.next
head.next = cur
cur = next
if __name__ == "__main__":
i = 1
# 链表的头结点
head = LNode(0)
cur = head
# 构造单链表
while i < 8:
tmp = LNode(i)
cur.next = tmp
cur = tmp
i += 1
print("原链表:", end=" ")
cur = head.next
while cur != None:
print(cur.data, end=" ")
cur = cur.next
print("\n逆序后:", end=" ")
reverse(head)
cur = head.next
while cur != None:
print(cur.data, end=" ")
cur = cur.next
原链表: 1 2 3 4 5 6 7
逆序后: 7 6 5 4 3 2 1
以上这种方法也只需要对单链表进行一次遍历,因此,时间复杂度为 O(N),其中, N 为
链表的长度。与方法一相比,这种方法不需要保存前驱结点的地址,与方法二相比, 这种方
法不需要递归地调用,效率更高 。