美文网首页Python程序员数据结构和算法分析
python算法-015将链表元素两两交换元素(交换值、就地翻转

python算法-015将链表元素两两交换元素(交换值、就地翻转

作者: DKider | 来源:发表于2019-03-13 21:21 被阅读39次

大鹏一日同风起,扶摇直上九万里。
假令风歇时下来,犹能簸却沧溟水。
世人见我恒殊调,闻余大言皆冷笑。
宣父犹能畏后生,丈夫未可轻年少。
——李白《上李邕》

在现代,别人对你的文章冷嘲热讽,你来一句:“你行你上啊!”他可能就没脾气了。但是要换李白,他真的会上,因为他真的行!


题目描述:将链表的每两个节点翻转。不允许用新的节点。
例如:
给定链表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,才能操作,不然会报错,这里我还没找到一个好的解释办法。要注意的是,最后一组没有换位置,可以把最后的四行语句注释掉,看看结果就知道了。
image.png

鉴于此,我把指针减少了,只用一个主指针cur,用(cur,cur.next)这样一组来代替slow,fast。
这样的好处是,不用考虑fast是否有next.next,只看cur就行。操作是一样的:


image.png

代码实现:

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

输出结果:


image.png

全部代码:

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),这是我寒假想的名字,还挺好,之前没有什么实际意义,现在它有了!

我会尽量加快写的速度,我还要留时间学其他的知识。加油吧!

相关文章

  • python算法-015将链表元素两两交换元素(交换值、就地翻转

    大鹏一日同风起,扶摇直上九万里。假令风歇时下来,犹能簸却沧溟水。世人见我恒殊调,闻余大言皆冷笑。宣父犹能畏后生,丈...

  • Swift - LeetCode - 两两交换链表中的节点

    题目 两两交换链表中的节点 问题: 给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。 说明: 你的算法只...

  • 【算法】冒泡排序

    基本思想: 把数组中相邻的元素两两比较,根据大小来交换元素位置。第一轮两两交换之后,可以得出最大值会在最右边;接着...

  • Java中的经典算法之冒泡排序

    Java中的经典算法之冒泡排序(BubbleSort) 原理:比较两个相邻的元素,将值大的元素交换至右端。 思路:...

  • 数据结构 排序

    排序算法总览 冒泡排序(Bubble Sort) 从前往后两两比较相邻元素的值,若为逆序则交换他们,直到(n-1+...

  • 2018-07-21

    排序算法之冒泡排序 冒泡排序算法原理:比较两个相邻的元素,将值大的元素交换至右端。 步骤:依次比较相邻的两个数,将...

  • 冒泡排序算法

    冒泡排序算法原理 比较两个相邻的元素,将值大的元素交换到右边。然后再剩下的数中,再找最大数,再交换到剩余数的最右边...

  • 冒泡排序2018-07-10

    /** * 排序 * 相邻元素两两对比 * 元素交换 * */ function bubbleSort(arr) ...

  • 常见排序算法

    记录几个常见的排序算法。冒泡排序算法思路: 第一步,比较相邻元素的大小 第二步,符合条件的元素交换位置,最值交换到...

  • 常见排序算法归纳

    各类排序算法 排序算法一般分类: 冒泡排序 原理 比较两个相邻的元素,将值大的元素交换至右端。 思路 依次比较两个...

网友评论

    本文标题:python算法-015将链表元素两两交换元素(交换值、就地翻转

    本文链接:https://www.haomeiwen.com/subject/dsxxmqtx.html