[路飞_链表的增删改查]先来熟悉熟悉链表

158 阅读3分钟

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

承接上文上文 作为前端来认识下链表认识链表

今天我们通过链表的增删改查进一步熟悉下链表

链表的增

  1. 在链表的最后加上一个节点: 类似于数组里的push

    1. 当对于一个空的链表push的时候,直接返回新的节点
    2. 非空的时候不断循环到最后一个节点 最后一个节点的指针指向新的节点, 然后返回这个链表
    function push(list, val) {
      const node = new ListNode(val)
      if (list === null) return node
      let cur = l
      while (cur.next !== null) {
        cur = cur.next
      }
    
      cur.next = node
      return list
    }
    
  2. 给链表的某个位置(n)添加上一个节点(val): 类似于数组里的splice的添加的使用

    1. 循环遍历找到第n个节点,然后 新的节点指向 这个节点, 这个节点的上个节点指向我们的这个新的节点
    2. 边界的一些处理 当n === 0 添加到头的则 新的节点指向list 当大于list节点长度则添加到最后
    3. 代码注释里有重点: 因为需要前一个节点所以 遍历到n - 1个 使用n-1的next来确定当前节点
    function appendN(l, n, val) {
      const node = new ListNode(val)
      if (n === 0) {
        node.next = l
        return newNode
      }
      let cur = l
      let i = 0
      while (cur.next !== null) {
         // 这里我们需要前一个节点 所以 第n个节点只用.next 获取 很重要
        if (i === n -1) {
            break
        }
        i++
        cur = cur.next
      }
    
      if (cur && cur.next) node.next = cur.next
      cur.next = node
      return l
    }
    

    虚头: 用于处理头部边界处理,也是重点

    function appendN(l, n, val) {
      const node = new ListNode(val)
      const head = new ListNode()
      head.next = l
    
      let i = 0
      let cur = head
      while (cur.next !== null) {
        if (i === n) {
          node.next = cur.next
          cur.next = node
          break
        }
        cur = cur.next
        i++
      }
    
      if (cur.next === null) {
        cur.next = node
      }
    
      return head.next
    }
    

链表的删

  1. 删除第n个节点: 类似于数组里 splice 删除的用方法

    1. 有可能删掉第一个 先创建虚头
    2. 循环遍历到底n个的前一个(n - 1), 是前一个的指针指向下一个(n.next)即可
    3. 返回虚头的next
     function removeList(l, n) {
      let head = new ListNode()
      head.next = l
      let cur = head
      let i = 0
      while (cur !== null) {
        if (i === n) {
          cur.next = cur.next.next
          break
        } else {
          cur = cur.next
        }
        i++
      }
    
      return head.next
    }
    
    
  2. 删除值是val的节点: 类似于数组里filter 过滤掉list里的值是val的节点

    1. 和删除第n个类似,修改判断
    2. 如果删除所有,循环到尾部,如果删除一个则break终止遍历
      const head = new ListNode()
      head.next = l
      let cur = head
    
      while (cur) {
        if (cur.next && cur.next.val === val) {
          cur.next = cur.next.next
        } else {
          cur = cur.next
        }
      }
    
      return head.next
    

链表的改

找到第n个节点,修改这个节点的val

function listPatch(l, n, val) {
  let i = 0
  let cur = l

  while (cur !== null) {
    if (i === n) {
      cur.val = val
      break
    }
    i++
    cur = cur.next
  }

  return l
}

链表的查

  1. 查询第index个并返回: 类似于数组里find
function listFind(l, index) {
  let cur = l
  let i = 0
  let res = null
  while (cur) {
    if (index === i) {
      res = cur
      break
    }
    i++
    cur = cur.next
  }
  return res
}
  1. 查找链表里第一个值等于val的 并返回是第几个节点: 类似于数组里findIndex/indexOf
function listFindIndex(l, val) {
  let cur = l
  let i = 0
  while (cur) {
    if (cur.val === val) {
      break
    }
    cur = cur.next
    i++
  }

  return cur !== null ? i : -1
}

总结

  • 改和查- 相对而言 改和查相对简单,只要了解链表循环遍历,找到我们需求调出循环

  • 增和删- 我们这里有几个算法题里经常用到的一些东西

    • 当前节点 下个节点 指针的变动
    • 虚头的创建,方便解决很多问题
  • 这个我们熟悉链表的开始,接下来我们就要开始去做链表的算法了