链表和双向链表的实现

前言


链表中的数据通过指针连接,添加、插入或删除节点只需要修改指针指向

在这里插入图片描述

实现思路

实现一个链表需要具备以下方法
  • 在链表尾部添加节点
  • 获取链表所有节点的数据
  • 链表指定位置插入元素
  • 获取链表指定位置的节点数据
  • 获取节点在链表中的位置
  • 更新链表指定位置的数据
  • 移除链表指定位置的节点
  • 移除链表中的指定节点
  • 判断链表是否为空
  • 获取链表长度
链表内部需要定义head指针和链表长度

实现代码

  • 定义head指针和length存储链表长度
  • 定义节点类
function LinkedList() {
  this.head = null
  this.length = 0

  function Node(data) {
    this.data = data
    this.next = null
  }
}
  • 在链表尾部添加节点
append(data) {
  //创建新节点
  let node = new Node(data)
  //是否是第一个节点
  if(this.length === 0) {
    //head指向新节点
    this.head = node
  } else {
    //获取第一个节点
    let current = this.head
    //获取链表最后一个节点
	while(current.next) {
      current = current.next 
    }
    //最后一个节点指向新节点
    current.next = node
  }
  //链表长度加一
  this.length += 1
}
  • 获取链表所有节点的数据
toString() {
  //声明空字符串存储链表节点数据
  let listString = ''
  //获取第一个节点
  let current = this.head
  //遍历所有节点
  while(current) {
    listString += current.data + ' '
    current = current.next
  }
  return listString
}
  • 链表指定位置插入元素
insert(position, data) {
  //判断位置是否有效
  if(position < 0 || position > this.length) return false
  //创建新节点
  let node = new Node(data)
  //是否插入到第一
  if(position === 0) {
    node.next = this.head
    this.head = node
  } else {
    //定义索引
    let index = 0
    //当前节点
    let current = this.head
    //上一个节点
    let previous = null
    //获取指定位置和上一个节点
    while(index++ < position) {
      previous = current
      current = current.next
    } 
    //上一个节点的指针指向新节点
    previous.next = node
    //新节点的指针指向当前节点
    node.next = current
  }
  //链表长度加一
  this.length += 1
  return true
}
  • 获取链表指定位置的节点数据
get(position) {
  //判断位置是否有效
  if(position < 0 || position >= this.length) return null
  let index = 0
  //获取第一个节点
  let current = this.head
  //获取指定位置的节点
  while(index++ < position) {
    current = current.next
  }
  //返回指定位置的节点数据
  return current.data
}
  • 获取节点在链表中的位置
indexOf(data) {
  //获取第一个节点
  let current = this.head
  let index = 0
  while(current) {
    //判断当前节点数据是否和传入数据相等
    if(current.data === data) {
     //返回位置
      return index
    }
    //获取下一个节点
    current = current.next
    index += 1
  }
  //没有找到节点
  return -1
}
  • 更新链表指定位置的数据
update(position, data) {
  //判断位置是否有效
  if(position < 0 || position >= this.length) return false
  let index = 0
  let current = this.head
  //获取指定位置节点
  while(index++ < position) {
    current = current.next 
  }
  current.data = data
}
  • 移除链表指定位置的节点
removeAt(position) {
  //判断位置是否有效
  if(position < 0 || position >= this.length) return false
  let current = this.head
  //是否移除第一个节点
  if(position === 0) {
    this.head = this.head.next
  } else {
    let index = 0
    let previous = null
    while(index++ < position) {
      previous = current
      current = current.next
    }
    //指定位置上一节点指向指定位置的下一节点
    previous.next = current.next
  }
  //长度减一
  this.length -= 1
  //返回移除节点
  return current
}
  • 移除链表中的指定节点
  • 判断链表是否为空
  • 获取链表长度
remove(data) {
 this.removeAt(this.indexOf(data))
}
isEmpty() {
  return this.length === 0
}
size() {
  return this.length
}

测试代码

//实例化链表
let linkedList = new LinkedList()
//链表尾部添加节点
linkedList.append('swt')
linkedList.append('mff')
linkedList.append('pty')
//获取链表节点数据
console.log(linkedList.toString())
//指定位置插入
linkedList.insert(1, 'cyw')
console.log(linkedList.toString())
//获取指定位置节点数据
console.log(linkedList.get(1))
//获取节点数据在链表中的位置
console.log(linkedList.indexOf('lbw'))
console.log(linkedList.indexOf('mff'))
//更新指定位置的数据
linkedList.update(0, 'wo')
//移除指定位置的节点
linkedList.removeAt(0)
console.log(linkedList.toString())
//移除指定数据的节点
linkedList.remove('mff')
console.log(linkedList.toString())
//判断链表是否为空
console.log(linkedList.isEmpty())
//获取链表长度
console.log(linkedList.size())

在这里插入图片描述

双向链表

双向链表的指针是双向的,前指针指向上一个节点,后指针指向下一个节点
head指向第一个节点,tail指向最后一个节点

在这里插入图片描述

双向链表实现思路

需要具备以下方法
  • 尾部插入元素
  • 任意位置插入元素
  • 获取所有节点数据
  • 正向遍历链表获取节点数据
  • 反向遍历链表获取节点数据
  • 获取指定位置的节点数据
  • 获取指定数据在链表中的位置
  • 更新指定位置的节点数据
  • 移除指定位置的节点
  • 移除指定数据的节点
  • 判断链表是否为空
  • 获取链表长度
定义head和tail分别指向第一个节点和最后一个节点

代码实现

/**
 * 双向链表
 */
function DoublyLinkedList() {
  //指向第一个节点
  this.head = null
  //指向最后一个节点
  this.tail = null
  //链表长度
  this.length = 0
  //创建节点类
  function Node(data) {
    this.data = data
    this.prev = null
    this.next = null 
  }
}
  • 尾部插入元素
append(data) {
  //创建新节点
  let node = new Node(data)
  //判断链表是否为空
  if(this.length === 0) { //链表为空
    this.head = node
    this.tail = node
  } esle { //链表不为空
    //新节点的前指针指向最后一个节点
    node.prev = this.tail
    //最后一个节点的后指针指向新节点
    this.tail.next = node
    //尾指针指向新节点
    this.tail = node
  }
  //链表长度加一
  this.length += 1
}
  • 向前遍历链表获取节点数据
forwardString() {
  //用于存储节点数据
  let string = ''
  //获取最后一个节点
  let current = this.tail
  //只要当前节点存在就将节点存储到字符串中并让当前节点等于上一个节点
  while(current) {
    string += current.data + ' '
    current = current.prev
  }
  return string
}
  • 向后遍历链表获取节点数据
backwardString() {
  //用于存储节点数据
  let string = ''
  //获取第一个节点
  let current = this.head
  //只要当前节点存在就将节点数据存储到字符串中并让当前节点等于下一节点
  while(current) {
    string += current.data
    current = current.next
  }
  return string
}
  • 获取所有节点数据
toString() {
 return this.backwardString()
}
  • 任意位置插入元素
insert(position, data) {
  //判断插入位置是否有效
  if(position < 0 || position > this.length) return false
  //创建新节点
  let node = new Node(data)
  //判断链表是否为空
  if(this.length === 0) { //链表为空
    this.head = node
    thi.tail = node
  } else { //链表不为空 判断插入位置
    if(position === 0) { //插入到第一个节点位置
      //新节点的后指针指向第一个节点
      node.next = this.head
      //第一个节点的前指针指向新节点
      this.head.prev = node
      //head指向新节点
      this.head = node
    } else if(position === this.length) { //插入到最后一个节点
      //最后一个节点的后指针指向新节点
      this.tail.next = node
      //新节点的前指针指向最后一个节点
      node.prev = this.tail
      //tail指向新节点
      this.tail = node
    } else { //插入到中间位置
      let index = 0
      let current = this.head
      //获取插入位置的节点
      while(index++ < position) {
        current = current.next
      }
      //新节点后指针指向当前节点
      node.next = current
      //新节点前指针指向上一个节点
      node.prev = current.prev
      //上一节点后指针指向新节点
      current.prev.next = node
      //当前节点前指针指向新节点
      current.prev = node
    }
  }
  this.length += 1
  return true
}
  • 获取指定位置的节点数据
get(position) {
  //判断位置是否有效
  if(position < 0 || position >= this.length ) return false
  //判断是向后遍历查找还是向前遍历查找
  if(this.length / 2 >= position) { //向后遍历
    let index = 0
    let current = this.head
    while(index++ < position) {
      current = current.next
    }
    return current.data
  } else { //向前遍历
    let index = this.length - 1
    let current = this.tail
    while(index-- > position) {
      current = current.prev
    }
    return current.data
  }
}
  • 获取指定数据在链表中的位置
indexOf(data) {
  let index = 0
  let current = this.head
  while(current) {
    if(current.data === data) {
      return index 
    }
    current = current.next
    index += 1
  }
  //没有找到
  return -1
}
  • 更新指定位置的节点数据
update(position, data) {
  //判断位置是否有效
  if(position < 0 || position >= this.length) return false
  //判断向后遍历还是向前遍历
  if( this.length / 2 > position) { // 向后遍历
    let index = 0
    let current = this.head
    //获取指定位置节点
    while(index++ < position) {
      current = current.next 
    }
    current.data = data
    return true
  } else { //向前遍历
    let index = this.length - 1
    let current = this.tail
    //获取指定位置节点
    while(index-- > position) {
      current = current.prev 
    }
    current.data = data
    return true
  }
}
  • 移除指定位置的节点
removeAt(position) {
  //判断位置是否有效
  if(position < 0 || position >= this.length) return false
  let current = this.head
  //判断链表长度
  if(this.length === 1) { //链表长度为1
    this.head = null
    this.tail = null
  } else {
    if(position === 0) { //移除第一个节点
      //第二个节点的前指针指向null
      this.head.next.prev = null
      //head指向第二个节点
      this.head = this.head.next
    } else if(position === this.length - 1) { //移除最后一个节点
      //当前节点为最后一个节点	
      current = this.tail
      //倒数第二个节点的后指针指向nul
      this.tail.prev.next = null
      //tail指向倒数第二个节点
      this.tail = this.tail.prev
    } else { //移除中间节点
      if(this.length / 2 >= position) { //向后遍历
        let index = 0
        //获取指定位置的节点
        while(index++ < position) {
          current = current.next
        }
        //指定位置节点的下一个节点前指针指向指定位置的上一个节点
        current.next.prev = current.prev
		//指定位置节点的上一个节点后指针指向指定位置的
        current.prev.next = current.next
      } else { //向前遍历
        let index = this.length - 1
        current = this.tail
        //获取指定位置的节点
        while(index-- > position) {
          current = current.prev
        }
        //指定位置节点的下一个节点前指针指向指定位置的上一个节点
        current.next.prev = current.prev
		//指定位置节点的上一个节点后指针指向指定位置的
        current.prev.next = current.next
	  }
    }
  }
  this.length -= 1
  return current.data
}
  • 移除指定数据的节点
remove(data) {
  return this.removeAt(this.indexOf(data))
}
  • 判断链表是否为空
  • 获取链表长度
isEmpty() {
  return this.length === 0
}
sieze() {
  return this.length
}

代码测试

let doublyLinkedList = new DoublyLinkedList()
doublyLinkedList .append('swt')
doublyLinkedList .append('mff')
console.log(doublyLinkedList .forwardString())
console.log(doublyLinkedList .backwardString())
doublyLinkedList .insert(0,'cyw')
console.log(doublyLinkedList .toString())
console.log(doublyLinkedList .get(0))
console.log(doublyLinkedList .get(2))
console.log(doublyLinkedList .indexOf('mff'))
console.log(doublyLinkedList .update(2, '巢怡雯'))
console.log(doublyLinkedList .toString())
console.log(doublyLinkedList .removeAt(2))
console.log(doublyLinkedList .remove('swt'))
console.log(doublyLinkedList .isEmpty())
console.log(doublyLinkedList .size())

在这里插入图片描述

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值