链表总结

来源:互联网 发布:凌志软件 编辑:程序博客网 时间:2024/06/14 13:22

1.快速找到未知长度单链表的中间节点

a.初级算法:

从头遍历到末尾,再次从头遍历到中间处。O(L+L/2) =O(3L/2)

b.高级算法:

利用快慢指针原理:设置两个指针fast 和mid,都指向单链表的头节点。其中fast的移动速度是mid的2倍。当fast指向末尾节点的时候,mid正好就在中间了。O(L/2)

public static int void getMidNode(MyList L){    MyList fast,mid;    fast = L.head;    mid = L.head;    while(fast.next != null){        if(fast.next.next!=null){            fast = fast.next.next;            mid = mid.next;        }        else            fast = fast.next;    }    return mid.data;}

2.判断链表中是否有环

利用快慢指针原理,最后快慢指针相撞。

1. 有环时求环的长度
记录碰撞点P,slow、fast指针从该点出发,再次碰撞所走过的操作数就是环的长度s。
2. 找出环的连接点
有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从头结点,碰撞点开始走(相同的速度),相遇的地方就是连接点。
证明:

假设单链表的总长度为L,头结点到环入口的距离为a,环入口到快慢指针相遇的结点距离为x,环的长度为r,慢指针总共走了s步,则快指针走了2s步。另外,快指针要追上慢指针的话快指针至少要在环里面转了一圈多(假设转了n圈加x的距离),得到以下关系:s = a + x;2s = a + nr + x;=>a + x = nr;=>a = nr - x;由上式可知:若在头结点和相遇结点分别设一指针,同步(单步)前进,则最后一定相遇在环入口结点,搞定!附图:

这里写图片描述

3. 求带环链表的长度
问题2中已经求出连接点距离头指针的长度,加上问题1中求出的环的长度,二者之和就是带环单链表的长度

3.判断两个无环链表是否相交,并找出相交点

a.转换为判断是否有环。将第一个链表的表尾部指向第二条链表的头部,再从第二个链表的头部进行遍历(如果有环,那么第二条的头节点就一定在环上)。

这里写图片描述

b.遍历两条链表,并判断最后一个节点是否相等,因为,如果相交,那么最后一个节点一定相同。

这里写图片描述

c.判断两个链表中是否存在地址一致的节点,就可以知道是否相交了。可以对第一个链表的节点地址进行hash排序,建立hash表,然后针对第二个链表的每个节点的地址查询hash表,如果它在hash表中出现,则说明两个链表有共同的结点。这个方法的时间复杂度为:O(max(len1+len2);但同时还得增加O(len1)的存储空间存储哈希表。这样减少了时间复杂度,增加了存储空间。以链表节点地址为值,遍历第一个链表,使用Hash保存所有节点地址值,结束条件为到最后一个节点(无环)或Hash中该地址值已经存在(有环)。

判断出两个链表相交后,找出其相交点。

法1:假设第一条和第二条链表的长度为len1,len2,然后找出较长的链表,并让其从|len1- len2|,开始遍历,逐个比较两个链表的值。
法2:将两个链表压栈,并比较两个栈出来的数据,直到两个数据不同时,就可以判断相交点。

问题的延伸:
如果原来的两个链表中有环怎么处理?
a.创建第一个链表的地址hash,直到所有节点都存入(终结条件就是添加新的hash时,hash表中已经存在了)。遍历第二个链表,并hash,判断是否在表中。
b.分三种情况:两条head都不在环上,都在环上,有一个在环上,这三种方式都可以用快慢指针进行判断。
这里写图片描述

3.用两个栈实现链表

  1. 方法一:创建两个栈S1,S2,始终维护S1作为存储空间,S2作为出栈的临时缓冲区,出完栈后,将数据倒回S1。
  2. 方法二:关键思路是,在有需要的时候再将S2的数据倒回S1,在连续性出栈,提高效率。入栈时判断S1是否为空,如果为空,将S2中的数据倒回S1,再压栈;出栈时,判断S2数据是否为空,如果不空,则直接出栈。
  3. 方法三:入栈时,将数据压入S1,出栈时,判断S2是否为空,如果为空,则将S1的数据倒入S2;如果S2不空,则直接从S2中出栈数据。
    总结:方法三的效率最高,但是也有问题,比如连续性的压栈,导致S1的空间耗尽,但是S2的空间不能拿来使用。
    这里写图片描述
0 0
原创粉丝点击