数据结构与算法 --- 链表(一)

256 阅读6分钟

链表

链表是非连续的、无序的数据结构,由一系列节点组成。

链表有很多种,今天先说一下单链表

  • 节点: 节点包含两部分, 一部分是存储数据元素的数据域, 一部分是指向下一个节点的指针域。
    下图中绿色部分是数据域, 蓝色部分是指针域。

  • 首尾节点:链表中第一个节点是首节点,最后一个节点是尾节点。

  • 有、无头链表: 首节点没有数据域的是有头链表;首节点有数据域的是无头链表。

链表有很多种,先介绍单向无头链表。(配图是有头链表)

链表的实现

节点

节点有数据域和指向下一个节点的指针域组成

function Node(data{
    this.data = data
    this.next = null
}

链表的方法

  • append 添加一个新节点
  • insert 向指定位置插入新节点
  • remove 删除指定索引节点
  • remove_head 删除首节点
  • remove_tail 删除尾节点
  • indexOf 返回指定节点的索引
  • get 返回指定索引的节点
  • head 返回首节点
  • tail 返回尾节点
  • length 返回链表长度
  • isEmpty 判断链表是否为空
  • clear 清空链表
  • print 打印整条链表

insert 方法

思路:

  • 要把 new_node 节点 8 插入到 2 的位置, 先找到索引为1 的节点 pre_node
  • 通过 pre_node.next 找到原来索引为2 的节点 next_node
  • 通过 pre_node.next 连接上 new_node
  • 通过new_node.next 连接上next_node
function insert(index, data{
    if(index < 0 || index > length) {
      return false
    }

    let new_node = new Node(data)
    if(index === 0) {
      new_node.next = head
    }
    if(index === length){ // 如果插入的位置是尾部
      tail.next = new_node  // 尾部节点连接上新节点
      tail = new_node   // tail 指针指向新节点
    }else {
      let pre_node = get_node(index -1)  // 获取 插入位置的前一个节点
      new_node.next = pre_node.next      // 新节点连接上原来该位置的节点
      pre_node.next = new_node           // 前一个节点连接上新插入的节点
    }

    length++
    return true
  }

remove 方法

思路:

  • 先找到上一个索引的节点 pre_node
  • 通过 pre_node.next 要删除的节点 del_node
  • 通过 pre_node.next.next 找到要删除节点的下一个节点 next_node
  • 通过 pre_node.next = next_node 删除 del_node
  • 通过 del_node = null 把del_node 清空
function remove(index{
    let del_node = null
    if(index < 0 || index > length - 1) {
      return false
    }
    if(index === 0) {
      head = head.next
      if(!head) {
        tail = null
      }
    }else {
      let pre_node = get_node(index - 1)
      del_node = pre_node.next
      let next_node = pre_node.next.next
      pre_node.next = next_node
      if(!del_node.next) { // 如果删除的是尾节点
        tail = pre_node
      }
    }
    del_node.next = null
    length--
    return del_node.data
  }

其他 链表的方法 如下,或 查看完整链表方法

function LinkList({
  let head = null
  let tail = null
  let length = 0

  this.append = function (data{
    let new_node = new Node(data)
    if (!head) {
      head = new_node
      tail = new_node
    } else {
      tail.next = new_node
      tail = new_node     
    }
    length++
  }

  this.print = function ({
    let curr_node = head
    let link_str = ''
    while (curr_node) {
      link_str += curr_node.data + ' --> '
      curr_node = curr_node.next
    }
    console.log(link_str)
    console.log('length:', length)
  }

  function get_node(index{
    if(index < 0 || index > length - 1) {
      return null
    }
    let curr_node = head
    let node_index = index
    while (node_index-- > 0) {
      curr_node = curr_node.next
    }
    return curr_node
  }

  this.insert = function (index, data{
    if(index < 0 || index > length) {
      return false
    }
    if(index === 0) {
      let new_node = new Node(data)
      new_node.next = head
    }
    if(index === length){
      let new_node = new Node(data)
      tail.next = new_node
      tail = new_node
    }else {
      let pre_node = get_node(index -1)
      let new_node = new Node(data)
      new_node.next = pre_node.next
      pre_node.next = new_node
    }

    length++
    return true
  }

  this.remove = function (index{
    let del_node = null
    if(index < 0 || index > length - 1) {
      return false
    }
    if(index === 0) {
      head = head.next
      if(!head) {
        tail = null
      }
    }else {
      let pre_node = get_node(index - 1)
      del_node = pre_node.next
      let next_node = pre_node.next.next
      pre_node.next = next_node
      if(!del_node.next) { // 如果删除的是尾节点
        tail = pre_node
      }
    }
    del_node.next = null
    length--
    return del_node.data
  }

  this.indexOf = function (data{
    let index = 0
    let curr_node = head
    while (curr_node) {
      if(curr_node.data === data) {
        return index
      }else {
        curr_node = curr_node.next
      }
      index++
    }
    return -1
  }

  this.get = function (index{
    const curr_node =  get_node(index)
    return curr_node ? curr_node.data : null
  }

  this.clear = function ({
    head = null
    tail = null
    length = 0
  }
}