大鹏一日同风起,扶摇直上九万里。
假令风歇时下来,犹能簸却沧溟水。
世人见我恒殊调,闻余大言皆冷笑。
宣父犹能畏后生,丈夫未可轻年少。
——李白《上李邕》
在现代,别人对你的文章冷嘲热讽,你来一句:“你行你上啊!”他可能就没脾气了。但是要换李白,他真的会上,因为他真的行!
题目描述:将链表的每两个节点翻转。不允许用新的节点。
例如:
给定链表Head->1->2->3->4->5->7->7->8
反转为链Head->2->1->4->3->7->5->8->7
这题是为了明天的题目做铺垫的,先来分析下这个题:本质上还是操作链表,之前我们做过类似的。不过,这次是翻转节点,节点有两个属性data和next,交换两个节点的值就可以完成了,这样不需要将节点位置改变。这太简单了,就像a=1,b=2,交换a,b的值一样那么简单,只需要用一个中间值tmp来保存就行:tmp=a a=b b=tmp
。主要的问题就是如何遍历的问题,这也是个不是问题的问题。用一个指针即可完成,但是对于明天的题,并没有太大帮助。
下面来看利用next属性,如何做:
利用next属性必然会改变节点的位置,也就是链表结构会变,先来看看怎样改变
图中我用红笔标出了操作顺序1、2、3、4:先pre->fast,然后fast->slow,最后slow->next,这里为什么会先把next->fast.next:因为在第二步时,得保存后面的链表,不然会丢失,这与a.b交换值是一个道理。这里的顺序也可以换成1、2、4、3,两个效果是一样的。
这里有一个注意的地方就是每次的循环条件:宗旨就是当后面的节点不够一组进行交换时,退出循环。但是如何知道后面不够一组呢?先来看下代码。
下面代码实现:
def function(head):
#判断链表是否为空,为空返回
if head.next is None or head.next.next is None:
return head
pre=head # 指向slow的前驱节点
slow=head.next
fast=slow.next
#slow和fast为相邻的节点
#next=fast.next
# 这里的循环条件要注意
# 链表的长度可能为奇数,也可能是偶数
# 每次四个指针会变换,因为是先操作再迭代下一组
# 再迭变换完后,如果fast指针后面只有一个元素,或者没有元素,这时
# 后面的无法再进行翻转,所以应该出循环,正常应该做完在判断的,
# 这里只能符合的才操作,因为用的指针多了一个。
while fast.next is not None and fast.next.next is not None:
next = fast.next #保存链表,因为要断开
pre.next=fast
fast.next=slow
slow.next=next
# # 上面的四句做的操作,见图
pre=slow
slow=next
fast=slow.next
#因为面的判断条件,最后一组,我们并没有翻转,这里操作下
next = fast.next
pre.next = fast
fast.next = slow
slow.next = next
return head
这里我用while fast.next is not None and fast.next.next is not None
,这一句看起来很臃肿。
这里我用了四个指针,链表的长度可能为奇数,也可能是偶数,每次四个指针会变换,因为是先操作再迭代下一组,在变换完后,如果fast指针后面只有一个元素,或者没有元素,这时后面的无法再进行翻转,所以应该出循环,按分析应该做完在判断的,但是因为涉及到一个next指针,每次都得确定还有next,才能操作,不然会报错,这里我还没找到一个好的解释办法。要注意的是,最后一组没有换位置,可以把最后的四行语句注释掉,看看结果就知道了。
鉴于此,我把指针减少了,只用一个主指针cur,用(cur,cur.next)这样一组来代替slow,fast。
这样的好处是,不用考虑fast是否有next.next,只看cur就行。操作是一样的:
代码实现:
def function(head):
if head is None or head.next is None:
return head
cur=head.next#当前遍历节点
pre=head#当前遍历节点的前驱节点
next=None#当前节点后继节点的后继节点
# 这里的循环条件可能不太一样,因为省掉了fast,所以考虑的东西就会变少。
while cur is not None and cur.next is not None:
next=cur.next.next
pre.next=cur.next
#这里可能一看不太好理解
# (cur.next).next
# 这样把cur.next看做一个节点,也就是之前的fast
cur.next.next=cur
cur.next=next
pre=cur
cur=next
return head
循环条件变了,我将他们放在一个文件里了,如果后者没问题,就可以把变换的链表变回去:
if __name__ == '__main__':
head = creatLink(6)
print("head:")
cur = head.next
while cur != None:
print(cur.data)
cur = cur.next
head = function_1(head)
print("\nAfterReverse_1:") # 这是用slow和fast的
cur = head.next
while cur != None:
print(cur.data)
cur = cur.next
head = function_2(head) # 这是cur
print("\nAfterReverse_2:")
cur = head.next
while cur != None:
print(cur.data)
cur = cur.next
输出结果:
全部代码:
import random
class LNode:
def __init__(self,arg):
self.data=arg
self.next=None
"""
题目描述:
给定链表Head->1->2->3->4->5->7->7->8
反转为链Head->2->1->4->3->7->5->8->7
要求:
方法:只用一个cur,用pre和next辅助反转。
"""
def creatLink(x):
i = 1
head = LNode(None)
tmp = None
cur = head
while i <= x:
n = random.randint(1, 9)
tmp = LNode(n)
cur.next = tmp
cur = tmp
i += 1
return head
#
#双指针法
def function_1(head):
#判断链表是否为空,为空返回
if head.next is None or head.next.next is None:
return head
pre=head # 指向slow的前驱节点
slow=head.next
fast=slow.next
#slow和fast为相邻的节点
#next=fast.next
# 这里的循环条件要注意
# 链表的长度可能为奇数,也可能是偶数
# 每次四个指针会变换,因为是先操作再迭代下一组
# 再迭变换完后,如果fast指针后面只有一个元素,或者没有元素,这时
# 后面的无法再进行翻转,所以应该出循环,正常应该做完在判断的,
# 这里只能符合的才操作,因为用的指针多了一个。
while fast.next is not None and fast.next.next is not None:
next = fast.next #保存链表,因为要断开
pre.next=fast
fast.next=slow
slow.next=next
# # 上面的四句做的操作,见图
pre=slow
slow=next
fast=slow.next
#因为面的判断条件,最后一组,我们并没有翻转,这里操作下
next = fast.next
pre.next = fast
fast.next = slow
slow.next = next
return head
def function_2(head):
if head is None or head.next is None:
return head
cur=head.next#当前遍历节点
pre=head#当前遍历节点的前驱节点
next=None#当前节点后继节点的后继节点
# 这里的循环条件可能不太一样,因为省掉了fast,所以考虑的东西就会变少。
while cur is not None and cur.next is not None:
next=cur.next.next
pre.next=cur.next
#这里可能一看不太好理解
# (cur.next).next
# 这样把cur.next看做一个节点,也就是之前的fast
cur.next.next=cur
cur.next=next
pre=cur
cur=next
return head
if __name__ == '__main__':
head = creatLink(6)
print("head:")
cur = head.next
while cur != None:
print(cur.data)
cur = cur.next
head = function_1(head)
print("\nAfterReverse_1:")
cur = head.next
while cur != None:
print(cur.data)
cur = cur.next
head = function_2(head)
print("\nAfterReverse_2:")
cur = head.next
while cur != None:
print(cur.data)
cur = cur.next
铺垫就到这里,明天的题目是:
将链表以k个一组翻转,不足k个也翻转,
给定链表Head->1->2->3->4->5->7->7->8
k=3
反转为链Head->3->2->1->7->5->4->8->7
会吗?
今天就这样,更多题目见GitHub,、微信:DKider。
Data Knowledge idea(我故意打的r),这是我寒假想的名字,还挺好,之前没有什么实际意义,现在它有了!
我会尽量加快写的速度,我还要留时间学其他的知识。加油吧!