玩转单链表

Posted weiyinfu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了玩转单链表相关的知识,希望对你有一定的参考价值。

玩指针是许多算法的精髓,就是要像六脉神剑一样,指针乱指一通之后,内存中的数据变得井然有序。

操作指针真的是太好玩了。下面出几道题。

一、不用额外空间翻转单链表

给定一个单链表,要求翻转之。

import random

"""
O(1)空间复杂度翻转链表
方法:one->two->three 三元组构成一个窗口,每次都翻转窗口内的元素,然后将
窗口从左往右滑动
"""

list_length = 4


class Node:
    def __init__(self, value, nex):
        self.value = value
        self.next = nex


def generate_list():
    a = Node(0, None)
    now = a
    for i in range(list_length):
        x = Node(random.randint(0, 100), None)
        now.next = x
        now = x
    return a.next


def print_list(x):
    while x:
        print(x.value, end=' ')
        x = x.next
    print()


def reverse(x):
    one = x
    two = one.next
    one.next = None
    # 如果只有一个元素,那么直接返回
    if not two: return x
    three = two.next
    while 1:
        two.next = one
        if not three: break
        temp = three.next
        three.next = two
        one = two
        two = three
        three = temp
    return two


l = generate_list()
print_list(l)
print_list(reverse(l))

二、两个无环单链表求第一个公共结点

方法非常简单:求出两个链表长度之差,记为x;然后让较长的链表先走x步;最后让两个链表携手并进。

时间复杂度:O(N+M)
空间复杂度:O(1)

三、判断单链表中是否有环,如果有环,找出环的第一个结点

有一个著名的ro算法,甲乙两个人同时从起点出发,甲每次走1格,乙每次走两格。如果甲乙二人有一人走到了终点,那么说明无环;如果甲乙二人都没有走到终点,而是经过s次走路之后,甲乙二人相遇了,说明有环,并且环的长度必然是s。因为在x次走路中,甲比乙少走了s步,也就是说环的长度是s。

----x--|----y----|
       |____z____|

如上图所示,将链表三部分的长度记为x,y,z,甲乙二人在y线段的最右侧相遇。那么甲走了x+y步,乙走了x+y+z+y步,显然(x+y)乘以2等于x+y+z+y。所以z=x。要想找到环中的第一个结点,只需要发现一个规律:让乙回到起点处(x最左侧)且将乙的步伐改为每次走一格,甲继续从y的右侧(相遇点)出发,两人下次相遇的地方就是环中的第一个结点,因为x=z!

有一道类似的趣题:无限一维空间中有两个生物,这两个生物之间无法进行交流,现在让你用如下四条汇编指令编程:
(1)move left
(2)move right
(3)if this position is visited,then goto 语句标号
(4)goto语句(程序中可以使用标号)

现在你需要开发一套汇编代码,给这两个生物安装上这套程序,保证这两个生物一定会相遇。
代码如下:

loop:
    if this position is visited,then goto movefast
    moveleft
    goto loop
movefast:
    moveleft
    moveleft
goto loop

原理是:两个生物一前一后同时往一个方向走,速度相同。如果看见了另一个生物的轨迹,就开始提速。这样就肯定能够追上前面的生物。

四、给定两个单链表,判定它们是否拥有共同结点

---------          \________
          /
_________/

这个问题比较复杂,需要分类讨论。
1、如果两个链表都是无环单链表,那么只需要判断最后一个结点是否相同即可!
2、如果一个链表是无环单链表,而另一个链表是有环的,那么这两个链表必然无公共结点!
3、如果两个链表都是有环的:
(1)假如两个链表相交,那么环必然是这两个链表的公共部分,只需要找到链表1环上的某个结点x,看看链表2是否会经过结点x
(2)假如两个链表不相交,那么它们的环必然不相交

五、求两个有环单链表的第一个公共结点(两个链表保证有公共结点)

首先用ro算法求出环上的某个点,把这个点当做链表的结尾,相当于把这个结点的next设为null。从而问题转换成了两条无环单链表求第一个公共结点。这个问题复杂度也是O(M+N)

参考资料

http://blog.csdn.net/v_JULY_v/article/details/6447013

以上是关于玩转单链表的主要内容,如果未能解决你的问题,请参考以下文章

数据结构 Java 版玩转链表双链表

数据结构单链表的增删查改,附代码+笔记gitee自取

单链表~增删查改(附代码)~简单实现

数据结构代码(用C语言) 单链表的插入和删除

单链表

数据结构--单链表简单代码实现(总结)