学习js数据结构与算法-链表(3)

126 阅读2分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。

个人觉得要想进大厂,就必须学习了解算法和数据结构,经历了多次面试之后,也知道了算法和数据结构的重要性,所以,我也打算从今天开始,进入学习,下载了一下电子书,边看书,边跟着书的例子来敲一下代码,下面就开始总结一下对算法和数据结构的学习吧。

第十三天:继续了解链表

前面,我们已经实现了链表类和节点类,还有在尾部添加节点的方法,下面我们来实现剩下的一些方法吧。

  • 从链表中移除元素。

    有两种从链表中移除节点的方法,一个是根据下标找到该节点,移除它,另一个是根据节点的值找到该节点并移除它,我们先实现根据下标找到节点并移除的方法。另一个方法之后就简单了

    function removeAt(index) {
    		// 首先是先处理边界值  
      	if(index >= 0 && index < this.count) {
    			let current = this.head
          // 如果是删除第一个节点
          if(index === 0) {
    				this.head = current.next
          }else {
            // 创建一个中间量,代表上一个
            let previous
            for(let i = 0; i < index; i++) {
              previous = current
              current = current.next
            }
            // 隔开找到的那个值
            previous.next = current.next
          }
          // 记得数量减一
          this.count--
          return current.element
        }
      	// 如果传入的值是非法值,则直接返回undefined
      	return undefined
    }
    

    如果是移除第一个节点,就是下面这个图

    ![image-20220208224940742](/Users/admin/Library/Application Support/typora-user-images/image-20220208224940742.png)

    如果是移除后面的,就是下面这个两个图,第一个是移除最后一个,第二个是移除中间的节点,其实两个都是一样的原理。

    ![image-20220208225033561](/Users/admin/Library/Application Support/typora-user-images/image-20220208225033561.png)

    ![image-20220208225041543](/Users/admin/Library/Application Support/typora-user-images/image-20220208225041543.png)

  • 找到目标位置

    我们可以把上面寻找到previous节点的方法给抽离出来

    function getElementAt(index) {
      if(index >= 0 && index < this.count) {
        	let node
      		for(let i = 0; i < index && node !== null; i++) {
            node = node.next
          }
        	return node
      }
    	return undefined
    }
    

    这样的话,我们的removeAt方法可以写成下面这样

    function removeAt(index) {
      let current = this.head
    	if(index === 0) {
        this.head = current.next
      }else {
        const previous = this.getElementAt(index - 1)
        current = previous.next
        previous.next = current.next
      }
      this.count--
      return current.element
    }
    
  • 在任意位置插入节点

    function insert(element, index) {
      // 还是和移除一样,判断边界值 
      if(index >= 0 && index < this.count) {
        const node = new Node(element)
        // 如果是插入第一个的操作
        if(index === 0) {
          const current = this.head
          node.next = current
          this.head = node
        }else { // 插入其他位置的操作
          const previous = this.getElementAt(index - 1)
          const current = previous.next
          node.next = current
          previous.next = node
        }
        this.count++
      }
      // 如果输入违法索引,返回false,证明插入失败
      return false
    }
    

    下面是插入第一个位置的操作图

image.png 下面是插入最后一个位置和其他任意位置的图,其他两个的操作原因完全一致

下面最后一个位置

image.png

下面是中间任意位置

image.png

  • indexOf

    和数组的一样,根据输入的元素,找到该元素在链表中的索引,上面我们已经实现了根据索引找到该节点了,现在我们实现根据值找到该索引

    function indexOf (element) {
      let current = this.head
    	for(let i = 0; i < this.count && current !== null; i++) {
        if(element === current.element) {
          return i
        }
        current = current.next
      }
      return -1
    }
    
  • 从链表中移除元素

    有了indexOf和removeAt方法之后,要实现这个方法就简单了

    function remove(element) {
    	let index = this.indexOf(element)
      let current = this.removeAt(index)
    }
    
  • 还有一些比较简单实现的方法,和上面学习的栈、队列差不多

    function isEmpty() {
      return this.head === null
    }
    function size() {
      return this.count
    }
    // 有了size,还可以直接这么实现isEmpty
    function isEmpty() {
      return this.size() === 0
    }
    function getHead() {
      return this.head
    }
    
  • 最后一个toString

    function toString() {
      if(this.head === null) return ''
      let current = this.head.next
      let stringRes = `${this.head.element}`
      for(let i = 1; i < this.count; i++) {
        stringRes = `${stringRes},${current.element}`
        current = current.next
      }
      return stringRes
    }