js数据结构 - 单向链表

单向链表

链表和数组一样,可以用于存储一系列的元素,但是链表和数组的实现机制完全不同。链表的每个元素由一个存储元素本身的节点和一个指向下一个元素的引用(有的语言称为指针或连接)组成。类似于火车头,一节车厢载着乘客(数据),通过节点连接另一节车厢。

  • head属性指向链表的第一个节点;
  • 链表中的最后一个节点指向null;
  • 当链表中一个节点也没有的时候,head直接指向null;

img

数组存在的缺点:

  • 数组的创建通常需要申请一段连续的内存空间(一整块内存),并且大小是固定的。所以当原数组不能满足容量需求时,需要扩容(一般情况下是申请一个更大的数组,比如2倍,然后将原数组中的元素复制过去)。
  • 在数组的开头或中间位置插入数据的成本很高,需要进行大量元素的位移。

链表的优势:

  • 链表中的元素在内存中不必是连续的空间,可以充分利用计算机的内存,实现灵活的内存动态管理
  • 链表不必在创建时就确定大小,并且大小可以无限地延伸下去。
  • 链表在插入和删除数据时,时间复杂度可以达到O(1),相对数组效率高很多。

链表的缺点:

  • 链表访问任何一个位置的元素时,都需要从头开始访问(无法跳过第一个元素访问任何一个元素)。
  • 无法通过下标值直接访问元素,需要从头开始一个个访问,直到找到对应的元素。
  • 虽然可以轻松地到达下一个节点,但是回到前一个节点是很难的。

链表中的常见操作:

  • append(element):向链表尾部添加一个新的项;
  • insert(position,element):向链表的特定位置插入一个新的项;
  • get(position):获取对应位置的元素;
  • indexOf(element):返回元素在链表中的索引。如果链表中没有该元素就返回-1;
  • update(position,element):修改某个位置的元素;
  • removeAt(position):从链表的特定位置移除一项;
  • remove(element):从链表中移除一项;
  • isEmpty():如果链表中不包含任何元素,返回trun,如果链表长度大于0则返回false;
  • size():返回链表包含的元素个数,与数组的length属性类似;
  • toString():由于链表项使用了Node类,就需要重写继承自JavaScript对象默认的toString方法,让其只输出元素的值;
// 代码实现
export class LNode { // 声明节点类
  constructor(data) {
    this.data = data
    this.next = null
  }
}

export class LinkedList {
  constructor() {
    this.head = null
    this.length = 0
  }
 // 向列表尾部添加一个元素
  append(data) {
    const lnode = new LNode(data)
    // 判断是不是第一个节点
    if (this.length == 0) {
      this.head = lnode
    } else {
      const currentNode = this.head
      // 找到最后一个节点,然后进行赋值】
      while (currentNode.next) {
        currentNode = currentNode.next
      }
      currentNode.next == lnode
    }
    this.length++
  }
// 实现向一个位置插入一个元素
  insert(position, data) {
    // 对position进行越界判断,当传入进来的值为负数,或者越界时,返回false
    if (position < 0 || position > this.length) return false
    const newNode = new LNode(data)
    // 判断position是不是为0
    if (position == 0) {
      newNode.next = this.head
      this.head = newNode
    } else {
      let index = 0
      let current = this.head
      var pre = null
      // 找到插入的位置以及位置的前一个
      while (index < position) {
        pre = current
        current = current.next
        index++
      }
      newNode.next = current
      pre.next = newNode
    }
    this.length++
    return true
  }
// 获得某一个位置的数据
  get(position) {
    if (position < 0 || position >= this.length) return null
    let current = this.head
    let index = 0
    while (index < position) {
      current = current.next()
      index++
    }
    return current.data
  }
//  根据某个位置返回数据元素
  indexOf(element) {
    let index = 0
    let current = this.head
    while (current) {
        if(current.data == element){
          return index
        }
        current = current.next
        index++
    }
    return -1
  }
// 修改某个位置的元素
update(position,element){
  if (position < 0 || position >= this.length) return null
    let current = this.head
    let index = 0
    while (index < position) {
      current = current.next()
      index++
    }
    current.data = element
    return true
}
// 从链表的特定位置移除一项
removeAt(position){
  if (position < 0 || position >= this.length) return null
  if(position == 0){
    this.head = current.next
  }else{
    let index =0
    let pre = null
    let current = this.head
    while(index < position){
      pre = current
      current = current.next
      index++
    }
    current = pre.next
    pre.next = current.next
  }
  this.length--
  return true
}
// 从链表中移除一项
  remove(element){
    return this.removeAt(this.indexOf(element))
}
// isEmpty() 判断链表是否为空
isEmpty() {
  return this.length === 0;
}

// size() 获取链表的长度
size() {
  return this.length;
}
// 实现toString方法
  toString() {
    const current = this.head
    const res = []
    while (current.next) {
      res.push(current.data)
      current = current.next
    }
    return res.join(' ')
  }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值