4.链表

  • 内存空间不连续,能实现灵活的内存动态管理
  • 链表创建时不需确定大小,大小可随需要而扩充
  • 在插入和删除数据时,时间复杂度可达到O(1)

4.1链表的火车结构

链表类似于火车,有一个火车头,火车头连接一个节点(车厢),节点(车厢)内有乘客(数据),并且此节点连接下一节点,以此类推

4.2链表的常见操作

  • append(element):向列表尾部添加一个新的项
  • insert(position,element):向列表的特定位置插入一个新的项
  • get(position):获取对应位置的元素
  • indexOf(element):返回元素在列表中的索引,如果列表中没有该元素则返回-1
  • update(positon,element):修改某个位置的元素
  • removeAt(position):从列表的特定位置移除一项
  • remove(element):从列表中移除指定的值
  • isEmpty():如果链表没有元素,返回true,否则返回False
  • size():返回链表包含的元素个数
  • toString():由于列表项使用了Nodeod,就需要重写继承自js对象默认的toString方法,让其只输出元素的值

4.3链表操作的实践

  1. 链表整体实现预览
function LinkedList () {
    function Node (data, next) {
        this.data = data
        this.next = next
    }
    this.head = null
    this.length = 0//记录当前数组的长度
    //append
    LinkedList.prototype.append = function (element) {}
    LinkedList.prototype.insert = function (position,element) {}
    LinkedList.prototype.get = function (position){}
    LinkedList.prototype.indexOf = function (element){}
    LinkedList.prototype.update = function (positon,element){}
    LinkedList.prototype.removeAt = function (position){}
    LinkedList.prototype.remove = function (element){}
    LinkedList.prototype.isEmpty = function (){}
    LinkedList.prototype.size = function (){}
    LinkedList.prototype.toString = function (){}
}
  1. append(element)方法实现
    向链表尾部追加数据有两种情况
  • 链表本身为空,新添加的节点为唯一节点
  • 链表不为空,在其他节点后追加节点
LinkedList.prototype.append = function (element) {
        var newNode = new Node(data)
        if (this.length == 0)//第一个节点
        {

            this.head = newNode
        }
        else {
            var currentNode = this.head
            while (currentNode.next != null) {//循环找到最后一个节点
                currentNode = currentNode.next
            }
            currentNode.next = newNode//将新节点插入
        }
        this.length+=1 
    }
  1. insert(position,element)方法实现
    在任意位置插入数据
  • 添加到第一个位置
    表示新添加的节点为头节点,此时需要将原来的头节点,作为新节点的next同时head应该指向该新节点
  • 添加到其他位置
  • 首先需要通过while循环,从头节点开始去遍历查找新节点需要插入的位置,并且在查找过程中保存上个节点与下个节点
  • 当找到正确位置后,将新节点的next指向下一个节点,上一个节点的next指向新节点
LinkedList.prototype.insert = function (position, data) {
        var currentNode = this.head
        var index = 0
        var newNode = new Node(data)
        if (position < 0 || position > this.length)
            return false
        if (position == 0) {
            this.head = newNode
            newNode.next = currentNode
        }
        else {
            while (currentNode != null) {
                if (index++ == position - 1)
                    break
                else {
                    currentNode = currentNode.next
                }
            }
            var q = currentNode.next
            currentNode.next = newNode
            newNode.next = q
        }
        this.length += 1
        return true

    }
  1. toString()方法实现
LinkedList.prototype.toString = function () {
        currentNode = this.head
        let elements = ''
        while (currentNode != null) {
            elements += currentNode.data + ' '
            currentNode = currentNode.next
        }
        return elements
    }
  1. get(position)方法
LinkedList.prototype.get = function (position) {
        var currentNode = this.head
        var index = 0
        if (position < 0 || position >= this.length)
            return false
        else {
            while (index++ < position) {
                currentNode = currentNode.next
            }
            return currentNode.data
        }
    }
  1. indexOf(element)方法
LinkedList.prototype.indexOf = function (element) {
        var currentNode = this.head
        var index = 0
        while (currentNode != null) {
            if (currentNode.data == element)
                return index
            else currentNode = currentNode.next
            index += 1
        }
        return -1
    }
  1. removeAt(position)方法
LinkedList.prototype.removeAt = function (position) {
    var index = 0
    var currentNode = this.head
    if (position < 0 || position >= this.length) return false
    if (position == 0)
        this.head = this.head.next
    else{
         while (index+1 < position) {
            currentNode = currentNode.next
            index+=1
        }
            currentNode.next = currentNode.next.next
    }
   
    
    this.length -= 1
    return true
}
  1. update(position,element)方法
LinkedList.prototype.update = function (position, element) {
        var currentNode = this.head
        var index = 0
        if (position < 0 || position >= this.length) return false
        while (index++ < position) {
            currentNode = currentNode.next
        }
        currentNode.data = element
        return true
    }
  1. remove(element)方法
//方法一:
  LinkedList.prototype.remove = function (element) {
    var currentNode = this.head
    var prev = this.head
    if (this.length == 0) return false
    if (this.length == 1 && element == currentNode.element) {
        this.head = null
         }
    else {
        while (currentNode != null) {
        if (element == currentNode.element) {
          if (currentNode === this.head) {
             this.head = currentNode.next}
              prev.next = currentNode.next
               break }
              else {
               prev = currentNode
               currentNode = currentNode.next
                        }
                    }
                }
this.length-=1
return true
            }
//方法二
LinkedList.prototype.remove = function (element) {
    var position = this.indexOf(element)
    this.removeAt(position)
}
  1. isempty()方法
LinkedList.prototype.isEmpty = function () {
    if (this.length == 0) return true
    else return false
}
  1. size()方法
LinkedList.prototype.size = function () {
    return this.length
}