js的数据结构05:处理环形链表

268 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情

前言

链表是一个动态的数据结构,没有扩容的操作;链表的意义在于:从开头Head每个链表都会有一个数据Data,还有一个指针Next它指向另外一个对象,另外一个对象也是这两个对象,往下推--直到最后一个数据只有一个Data,没有指针。

概念

链表可能是有环形的,如果有的话,每个元素都指向next,那么这就进入了死循环,所以要遍历判定链表内有没有环形

stateDiagram-v2
1 --> 2
2 --> 3
3 --> 4
4 --> 3

如果大批量数据的链表,设定固定的时间或者固定的条件,来判定它是否是环形,这种方式比较简单粗暴

var count = 1;
while(head){
  count++
  head = head.next
  if(count > 100){
    return true
  }else{
    return false
  }
}

每次遍历,把当前的指针赋值给当前的head,这样一直循环,粗暴的判定如果遍历次数大于100则进入了环形

环形遍历

  • 不考虑内存情况 通过HASH表,来记录,或者使用set()来进行存储,通过遍历,如果在head中发现了head那就出现了环形,如果不是则把当前的head存储到对象内
let set = new Set()
while(head){
  let set = new Set()
  if(set.has(head)){
    return true
  }else{
    set.add(head)
  }
  head = head.next
}
  • 考虑内存情况 链表数据量比较大,new Set()方法的空间复杂度量级和链表有很大的关系,原因:直到遍历完最后一个才会跳到第二个继续遍历,所以new Set()会变得巨大
var s = head;
var f = head;

需要两个快慢指针,快指针和慢指针会进行内外循环的操作

while(f && f.next){
    f = f.next.next
    s = s.next
    if(f == s){
       // 有环形
    }
}
// 遍历结束,无环形

通过遍历,每次快指针跑两步,也就是跳到下下指针,满指针跑一步跳到下一个指针

如果快指针f追上慢指针s,它们两个相等,那么就说明,该链表是环形的

最后

通过O(1)方式实现,如果链表长度是N,链表内的每个数据都会遍历到,而且空间复杂度也会很小。