(1.2.1.1)单链表的逆转倒置、验环、倒数第M个节点和相交

前端之家收集整理的这篇文章主要介绍了(1.2.1.1)单链表的逆转倒置、验环、倒数第M个节点和相交前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

(1)反向逆置


  1. //逆置单向链表
  2. //通过三个指针遍历 O(n)
  3. LNode*ListInverse(LNode*L)
  4. {
  5. if(L==NULL)
  6. returnNULL;
  7. if(L->Next==NULL)returnL;
  8. LNode*pre=L->Next;
  9. LNode*cur=pre->Next;
  10. LNode*next=cur->Next;
  11. pre->Next=NULL;
  12. cur->Next=pre;
  13. pre=cur;
  14. cur=next;
  15. while(cur!=NULL)
  16. next=cur->Next;
  17. }
  18. L->Next=pre;
  19. }

[html] view plain copy
@H_403_114@
  • //头插法遍历
  • copy
      publicvoidReversLinkList(LinkList<int>H)
    1. {
    2. Node>p=H.Next;
    3. Node>q=newNode>();
    4. H.Next=null;
    5. while(p!=null)
    6. {
    7. q=p;
    8. p=p.Next;
    9. q.Next=H.Next;
    10. H.Next=q;
    11. }


    (2)验证环


    正常链表的尾节点的链域是NULL,有环就不存在NULL了!对了,用一指针轮询,不断地p=p->next;若是看到了p为NULL,则表明无环!否则,就是有环。这个想法挺好,但是有环,会进入死循环的。有

    办法是有的:使用两指针,一快一慢,都从头开始轮询,若有环,则慢的肯定可以被快的反超,因为此时大家都像是在围绕着环形跑道赛跑;若是一正常链表,则肯定会遇到NULL,好了,问题解决了。

    1. boolhasLoop(Node*head)
    2. {
    3. if(head==NULL)//链表为空
    4. returnfalse;
    5. Node*p,*q;
    6. p=q=head;//两个指针从同一点出发,当然也可以一前一后
    7. while(p&&q)
    8. p=p->next;//一次一步
    9. q=q->next->next;//一次两步
    10. if(p==q)//相遇,肯定有环
    11. true;
    12. }
    13. false;//出现了NULL,也就无环
    14. }

    (3)倒数第M个节点

    两指针,一指针先从头移动k次,此时两指针间隔k(就是要这个差距),此时两指针同时移动,快慢一样,等到先走的指针移动到NULL,第二个指针不就是倒数第k个
      voidendOfK(Node*head,intk)
    1. if(head==NULL)
    2. printf("链表为空!");
    3. return;
    4. Node*p,*q;
    5. p=q=head;
    6. intcount=0;
    7. while(p&&count<k)
    8. p=p->next;
    9. count++;
    10. if(p==NULL&&count!=k)//update:这里原先只有p==NULL,更新后加上count!=k,大家想想为什么?
    11. {
    12. printf("k值过大!\n");
    13. return;
    14. }
    15. while(p)
    16. q=q->next;
    17. printf("倒数第%d个节点是%d\n",k,q->data);
    18. }

    (4)相交


    一指针沿着其中一链表走到尾节点处等着,另一链表的指针也从头走到尾,若能在尾处相遇,则两链表在某节点处相交。
    寻找相交节点
    不妨遍历每个链表保存最后一个节点,看看最后一个节点是否是同一个节点,这种情况时间复杂度是O(length1 + length2)。基本也不需要什么空间,似乎是一个不错的想法哦,那么怎么找到第一个相交节点呢?可以遍历的过程中记录链表的长度L1和L2(假设L1>L2)这是遍历找到第一个链表中的第L1 - L2节点,然后链表一从第L1-L2个节点开始遍历,链表二从第一个节点遍历,每次前进一步,直到找到第一个相同的节点,则可以认为两个链表存在相交节点,并且该点即为第一个相交节点(原来这里写错了,感谢Ider指出这个错误)。这种解法的时间复杂度也是线性的,但是如果两个链表长度相差不多时,时间复杂度还是不错的。

    (10)寻找环的入口点

    1. 遍历链表,将已经遍历过的节点放在一个hash表中,如果一个节点已经存在hash表中,说明有环。时间:O(n) 空间:O(n)

    2.寻找环的入口点: 当fast按照每次2步,slow每次一步的方式走,发现fast和slow重合,确定了单向链表有环路。接下来,让fast回到链表的头部,重新走,每次步长1,那么当fast和slow再次相遇的时候,就是环路的入口了。

    证明:在fast和slow第一次相遇的时候,假定slow走了n步,环路的入口是在p步,那么

    slow走的路径: p+c = n; c为fast和slow相交点 距离环路入口的距离

    fast走的路径: p+c+k*L = 2*n; L为环路的周长,k是整数

    显然,如果从p+c点开始,slow再走n步的话,还可以回到p+c这个点。

    同时,fast从头开始走,步长为1,经过n步,也会达到p+c这点。

    显然,在这个过程中fast和slow只有前p步骤走的路径不同。所以当p1和p2再次重合的时候,必然是在链表的环路入口点上。

    猜你在找的设计模式相关文章