双链表之将当前元素对应节点向前,向后移动n位

623 阅读4分钟

前言:今天看了一手数据结构的双链表, 双链表的定义呢,就是说节点有两个指针,即一个pre,一个next。pre指向其前驱,next指向其后续,所以叫做双链表呐(这名字多么科学^_^)

正文:说正事,实现在双链表中将当前节点【叫他原节点】元素向前、向后移动n位。

思路: 向前移动n位:找到当前元素的节点,然后在找到向前移动n+1位后的节点【叫他q节点】,剩下的就是将原节点的从原来的位置移出,然后将它加入到q节点的下一位即可。(向后移动n位也是同样的思想,看下边code可否?)

直接上代码


function Node(element) {
  this.element = element
  this.next = null //指向后继节点
  this.previous = null //指向前驱节点
}

// DoubleList提供对链表进行操作的方法,他的唯一属性就是使用Node对象来保存该链表的头结点
function DoubleList() {
  this.head = new Node('head')
  // head节点的next属性初始化为null,当有新元素插入时,next会指向新的元素
  this.find = find
  this.insert = insert
  this.display = display
  this.advance = advance //advance(ele,n),将目标元素对应的节点向前移动n个位
  this.back = back //back(ele,n),将目标元素对应的节点向前移动n个位
}

function find(ele) {
  // 遍历链表,查找给定的数据后返回包含给定数据的节点
  var currNode = this.head //从头结点查找起
  while (currNode.element != ele) {
    currNode = currNode.next
  }
  return currNode
}

// 在ele元素对应的节点后插入newEle对应的节点
function insert(newEle, ele) {
  var newNode = new Node(newEle)
  var current = this.find(ele) //找到插入节点的位置
  newNode.next = current.next //新节点指向插入位置的后一个
  newNode.previous = current
  current.next = newNode //插入位置的前一个节点的next指向当前位置节点
}

function display() {
  const res = []
  var current = this.head.next
  while (current !== null) {
    res.push(current.element)
    current = current.next
  }
  console.log(res.toString())
}

// 当前元素向前移动n个位置
function advance(ele, n) {
  // 实现思路:1. 找到当前的节点current,
  const current = this.find(ele)
  if (n <= 0 || isNaN(n)) {
    console.log('传入数字不合法')
    return false //传入位置不合法
  }
  if (!current || !current.previous) {
    console.log('你这个元素根本没有或者处在第一个位置,你还想向前移动,老哥!')
    return false //操作当然不成功拉
  }
  let pn = current //暂存当前节点
  // 2. 然后在依次遍历到要移动到的节点位置前一个节点pn
  while (pn.previous && n + 1 > 0) {
    pn = pn.previous
    n--
  }
  if (!current.next) {
    // 如果当前的下一个节点为空,则直接将前一个节点指向null
    current.previous.next = null
  } else {
    // 3. 然后将current.next.previous = current.previous //将当前节点的下一个节点指向当前节点的前一个节点
    current.next.previous = current.previous
    current.previous.next = current.next
  }
  //     再current.previous.next = current.next //将当前节点的上一个节点指向当前节点的下一个节点
  //     (这两步类似于删除当前节点,但是是‘类似’)因为我并没有释放当前节点
  // 4. 将pn.next.previous = current //将插入位置的previous指向当前节点
  //     再current.next = pn.next,current.previous=pn,pn.next  = current
  current.next = pn.next
  pn.next.previous = current
  current.previous = pn
  pn.next = current

  return true
}
// 当前元素向后移动n个位置
function back(ele, n) {
  // 思路:
  //1.找到元素为ele的节点current
  const current = this.find(ele)
  let temp = current //便于遍历
  if (n <= 0 || isNaN(n)) {
    console.log('传入数字不合法')
    return false //传入位置不合法
  }
  if (!current || !current.next) {
    console.log(
      '你要移动的元素根本不存在或处于最后一个了,还怎么向后移动,老兄'
    )
    return false //so fail
  }
  // 2.找到移动向后移动n个的位置的节点
  while (temp.next && n > 0) {
    temp = temp.next
    n--
  }
  // 将current的上一个节点指向current的下一个节点,
  // 将current的下一个节点的previous指向current的上一个节点(这两步是为了以移出当前节点的位置)
  current.previous.next = current.next
  current.next.previous = current.previous
  // 找到后呢,看下找到的节点.next是不是为null
  if (!temp.next) {
    //如果找到的下一个节点为空,则直接将当前节点插入都尾部即可
    current.next = null
    temp.next = current
    current.previous = temp
  } else {
    current.next = temp.next
    temp.next.previouse = current
    temp.next = current
    current.previous = temp
  }
  return true
}

var dlist = new DoubleList()
// insert(x2,x1)在元素为x1对应的节点后插入元素为x2的对应节点
dlist.insert('jake1', 'head')
dlist.insert('jake2', 'jake1')
dlist.insert('jake3', 'jake2')
dlist.insert('jake4', 'jake3')
dlist.display() //jake1,jake2,jake3,jake4

// 将jake4向前移动1个位置
dlist.advance('jake4', 1)
dlist.display() //jake1,jake2,jake4,jake3

// 然后将jake4向后移动1个位置,回到原来位置
dlist.back('jake4', 1)
dlist.display() //jake1,jake2,jake3,jake4