数据结构---链表

2023-11-19

目录

链表的概念

封装单项链表

封装链表结构

append方法(追加元素)

toString方法(转字符串)

insert方法(插入元素)

get方法(获取元素)

indexof(获取索引)

update修改某个位置的元素

removeAt方法(删除元素,根据索引)

remove(删除数据,根据元素)

isEmpty&&size方法

单想链表vs双向链表

封装双向链表

双向链表的特点

 封装链表结构

append方法(追加元素)

 toString方法(转字符串)

insert    在任意位置插入数据

get (根据索引查询数据)

indexof(获取索引)

update修改某个位置的元素

removeAt方法(删除元素,根据索引)

remove(删除数据,根据元素)

isEmpty&&size方法

获取第一个元素&&获取最后一个元素

完整代码

单向

双向


链表的概念

数组

要存储多个元素(或称为列表)可能是最常用的数据结构

数组创建通常需要申请一段连续的内存空间 (一整块内存),并且大小是固定的(大多数的编程语言数组是固定的,所以当当前数组不能满足需求时),需要扩容(一般情况下是申请一个更大的数组,比如两倍,然后将原来的数组复制过去)

数组开头或中间插入数据的成本很高,需要进行大量的元素位移

链表

 

链表类似于火车,有一个火车头,火车头会自动链接一个节点,节点上有乘客(类似于数据)并且这个节点会自动连接下一个节点

要存储多个元素,另外一个选择就是链表,

但不同于数组,链表中的元素不必是连续的空间

链表的每一个元素由一个存储元素本身的节点指向下一个元素的引用(有些语言称为指针或者连接)组成

内存空间不必是连续的,可以充分利用计算机的内存,实现灵活的内存动态管理,链表不必在创建时肯定大小,并且大小可以无限延伸下去,链表在插入和删除数据时, 可以达到O1,相对于数组效率高很多

链表访问任何一个位置的元素时,都需要从头开始访问(无法跳过第一个元素访问任何一个元素)无法通过下标直接访问元素,需要从头一个一个访问

封装单项链表

封装链表结构

LinkedList head指针最开始为null     length保存长度

Node内部节点类存放数据和指针

     //封装链表类
        function LinkedList() {
            //内部的类,节点类
            function Node(data) {
                this.data = data
                this.next = null
            }
            //属性
            this.haed = null//指针最开始
            this.length = 0

        }

append方法(追加元素)

 链表本身是空的, 比如这种情况下我们插入了一个15作为元素

链表中已经有元素了, 需要向最后的节点的next中添加节点.

  • 这个时候要向链表的尾部添加一个元素, 首先我们需要找到这个尾部元素.
  • 记住: 我们只有第一个元素的引用, 因此需要循环访问链表, 直接找到最后一个项.(见代码2.1)
  • 找到最后一项后, 最后一项的next为null, 这个时候不让其为null, 而是指向新创建的节点即可.

向列表追加数据可能有两种情况:列表本身为空,新添加数据时唯一节点,链表不为空,需要向其他节点追加节点         

             // append 向列表尾部添加一个新的项
            LinkedList.prototype.append = function (data) {
                //创建新节点
                let newNode = new Node(data)
                //判断是否添加的是第一个节点
                if (this.length == 0) {//是第一个节点
                    this.haed = newNode
                } else {
                    //找到最后一个节点
                    let current = this.haed
                    while (current.next) {
                        current = current.next
                    }
                    //最后节点的next指向新节点
                    current.next = newNode
                }
                //长度加1
                this.length += 1
            }

toString方法(转字符串)

从head开头,获取列表任意元素都必须从第一个节点开头,循环遍历每一个节点,并且取出其中的element拼接成字符串 将最终字符串返回

    //toString方法
            LinkedList.prototype.toString = function () {
                //定义变量
                let current = this.haed
                let listString = ''
                //循环获取每一个节点
                while (current) {
                    listString += "," + current.data
                    current = current.next
                }
                return listString.slice(1)
            }

insert方法(插入元素)

添加到第一个位置:

  • 添加到第一个位置, 表示新添加的节点是头, 就需要将原来的头节点, 作为新节点的next
  • 另外这个时候的head应该指向新节点.

添加到其他位置:

  • 如果是添加到其他位置, 就需要先找到这个节点位置了.
  • 我们通过while循环, 一点点向下找. 并且在这个过程中保存上一个节点和下一个节点.
  • 找到正确的位置后, 将新节点的next指向下一个节点, 将上一个节点的next指向新的节点.

 

添加到第一个位置:表示新添加的节点是头,作为新节点的next 这个时候的next指向新节点

添加到其他位置:如果是添加到其他位置,就需要先找到这个节点的位置,通过while循环,一点点的向下找,并且在这个过程中保存上一个节点和下一个节点

找到正确位置后,将新节点的next指向下一个节点,将上一个节点的next指向新的节点

      LinkedList.prototype.insert = function (position, dada) {
                // 对position进行判断
                if (position < 0 || position > this.length) return false

                // 根据data创建newNode
                let newNode = new Node(data)

                // 判断插入的位置是否为第一个
                if (position = 0) {
                    //把指针赋值给新节点,在把指针修改为新节点的指针
                    newNode.next = this.haed
                    this.haed = newNode
                } else {
                    let index = 0
                    let previous = null
                    let current = this.haed
                    while (index++ < position) {
                        previous = current
                        current = current.next
                    }
                    newNode.next = current
                    previous.next = newNode
                }
                //长度加1
                this.length += 1
                return true
            }

get方法(获取元素)

越界判断:当length等于0的时候直接返回最后一个的数据 假如查询为2,每次index++ 重新赋值指针相等之后直接退出返回数据

          LinkedList.prototype.get = function (position) {
                //越界判断
                if (position < 0 || position >= this.length) return null
                //获取对应的data
                let current = this.haed
                let index = 0
                //position=2
                // index = 0 current=下一个指针
                // index = 1 current=下一个指针
                // index = 2 current=数据
                while (index < position) {
                    index++
                    current = current.next
                }
                return current.data
            }
    

indexof(获取索引)

index为索引 current为最开始的指针 遍历查询每次索引和指针加1 如果传入的data跟数据对应的 data相等 返回数据 没有匹配项返回-1

   LinkedList.prototype.inexOf = function (data) {
                // 定义变量
                let current = this.haed
                let index = 0
                //开始查找
                while (current) {
                    if (current.data == data) {
                        return index
                    }
                    current = current.next
                    index += 1
                }
                return -1
            }
        

update修改某个位置的元素

类似于get方法,找到指定元素修改启内容

      LinkedList.prototype.update = function (position, element) {
                //越界判断
                if (position < 0 || position >= this.length) return false
                //查找正确的节点
                let current = this.haed
                let index = 0
                while (index < position) {
                    index++
                    current = current.next
                }
                // 将position位置的node的data改为newdata
                current.data = element
                return true
            }

removeAt方法(删除元素,根据索引)

移除第一项的信息:

  • 移除第一项时, 直接让head指向第二项信息就可以啦.
  • 那么第一项信息没有引用指向, 就在链表中不再有效, 后面会被回收掉.

移除其他项的信息:

  • 移除其他项的信息操作方式是相同的.
  • 首先, 我们需要通过while循环, 找到正确的位置.
  • 找到正确位置后, 就可以直接将上一项的next指向current项的next, 这样中间的项就没有引用指向它, 也就不再存在于链表后, 会面会被回收掉.

    LinkedList.prototype.removeAt = function (position) {
                if (position < 0 || position >= this.length) return null
                let current = this.haed
                //判断是否删除的为第一个节点
                if (position == 0) {
                    this.haed = this.haed.next
                } else {
                    let index = 0
                    let previous = null//前一个节点
                    while (index++ < position) {
                        previous = current
                        current = current.next
                    }
                    //前一个节点的next指向,current的next
                    previous.next = current.next
                }
                this.length -= 1
                return current.data
            }

remove(删除数据,根据元素)

//获取data在列表中的数据,根据位置信息删除数据


            // remove
            LinkedList.prototype.remove = function (data) {
                //获取data在列表中的数据
                let position = this.inexOf(data)
                //根据位置信息删除数据
                return this.removeAt(position)
            }

isEmpty&&size方法

 LinkedList.prototype.isEmpty = function (data) {
                return this.length == 0
            }
            LinkedList.prototype.size = function () {
                return this.length
            }

单想链表vs双向链表

单向链表

只能从头遍历到尾或者从尾遍历到头(一般从头到尾),也就是链表的相连过程是单向的,实现的原理是上一个链表的指向下一个的引用

我们轻松可以到达下一个节点,但是回到前一个节点是很难的

双向链表

既可以从头遍历到尾,也可以从尾遍历到头。也就是链表的相连是双向的,一个节点既有向前链接的引用也有向后链接的引用

每次在插入或者删除某个节点的时候需要处理四个引用,而不是两个占用的空间更大些

封装双向链表

双向链表的特点

可以使用一个head和一个tail指向头部或者尾部的节点

每一个节点都有三个部分组成;前一个节点的指针(prev)保存元素的(item)后一个节点(next)

双向链表的第一个节点的prv是null,最后一个节点的next是null

 封装链表结构

   function DoublyLinkedList() {
            // 内置类:节点类
            function Node(data) {
                this.data = data
                this.next = null
                this.prev = null // 新添加的
            }
            //属性
            this.head = null
            this.tail = null
            this.length = 0
        }

append方法(追加元素)

向列表追加数据可能有两种情况:列表本身为空,新添加数据时唯一节点,链表不为空,需要向其他节点追加节点    (找到最后一个节点把指针指向新节点)

    // 在尾部追加数据
            DoublyLinkedList.prototype.append = function (element) {
                // 1.根据元素创建节点
                var newNode = new Node(element)

                // 2.判断列表是否为空列表
                if (this.head == null) {
                    this.head = newNode
                    this.tail = newNode
                } else {
                    this.tail.next = newNode
                    newNode.prev = this.tail
                    this.tail = newNode
                }

                // 3.length+1
                this.length++
            }

 toString方法(转字符串)

reverseString反向遍历的方法:current获取最后一个元素 每次遍历current重新赋值为上个节点的指针

forwardString:正向遍历的方法 head从第一项开始遍历 current每次为下一个节点的指针

toString转字符串 默认正项遍历 调用forwardString


            // 正向遍历的方法
            DoublyLinkedList.prototype.forwardString = function () {
                //定义变量
                let current = this.head
                let forwardStr = ''

                // 依次向后遍历获取每一个节点
                while (current) {
                    forwardStr += "," + current.data
                    current = current.next
                }

                return forwardStr.slice(1)
            }

            // 反向遍历的方法
            DoublyLinkedList.prototype.reverseString = function () {
                var current = this.tail
                var reverseStr = ""
                // 依次向前遍历获取每一个节点
                while (current) {
                    reverseStr += "," + current.data
                    current = current.prev
                }

                return reverseStr.slice(1)
            }

            // 实现toString方法
            DoublyLinkedList.prototype.toString = function () {
                return this.forwardString()
            }

insert    在任意位置插入数据

情况一: 将元素插入到头部(position === 0)

  • 事实上, 将元素插入到头部是比较简单. 只是它有分成了两种情况.
  • 情况一: 列表为空. 那么直接让head/tail指向newNode即可
  • 情况二: 列表不为空, 这个时候需要修改原来head的prev指向新节点. 新节点的next指向原来的head. 并且head现在要指向newNode

情况二: 将元素插入到尾部(position === length)

  • 这种情况比较简答了, 因为我们在append方法中已经处理过了.
  • 注意: 这里不需要判断元素为空的情况, 因为在position === 0的时候, 我们已经处理过了. 所以到这里的时候, 肯定不为空.

情况三: 将元素插入到中间位置

  • 情况三是比较复杂一些的, 但是我们理清楚它的逻辑关系也就比较简单了.
  • 首先, 我们需要找到正确的插入位置. 通过while循环, 这个并不难, 因为我们在单向链表的时候已经找过了.
  • 查找正确的位置后, 需要进行插入操作.
  • 首先, 你的newNode的next/prev必然要指向前后的节点, 也就是current和previous
  • 其次, 而current的prev需要指向newNode, 而previous的next需要指向newNode.
  • 逻辑搞定, 并没有想象中的复杂, 详细看图解.

代码解析

  • 判断列表为空head,tail 等于茶插入的节点
  • 在第一个位置插入数据:原来的第一个节点的prev=指向改变之后的第一个节点,插入节点的下一个节点是当前节点,改变头部的节点为新插入的节点
  •  插入到最后的情况:新节点的前一个节点,等于最后一个节点,原来的最后一个节点=插入的节点,改变指向尾部的节点为新节点
  • 任意位置插入: //插入节点的下一个节点指针为查询到的下一个节点,插入节点的上一个节点指针为查询到的上一个节点,上一个节下一个指针=当前节点  ,查询到的上一个节指针=插入的节点 
          DoublyLinkedList.prototype.insert = function (position, element) {
                // 1.判断越界的问题
                if (position < 0 || position > this.length) return false
                //根据data创建新节点
                var newNode = new Node(element)
                //判断列表是否为空
                if (this.length == 0) {
                    this.head = newNode
                    this.tail = newNode
                } else {
                    //判断position是否为0
                    if (position == 0) {//第一个节点
                        //原来的第一个节点的prev指向改变之后的第一个节点
                        this.head.prev = newNode
                        // 插入节点的下一个节点是当前节点
                        newNode.next = this.head
                        // 改变头部的节点为新插入的节点
                        this.head = newNode
                    } else if (position == this.length) {//最后一个节点
                        //新节点的前一个节点,等于最后一个节点
                        newNode.prev = this.tail
                        //原来的最后一个节点=插入的节点
                        this.tail.next = newNode
                        //改变指向尾部的节点为新节点
                        this.tail = newNode
                    } else {//其他情况
                        let current = this.head
                        let index = 0
                        while (index++ < position) {
                            current = current.next
                        }
                        //插入节点的下一个节点指针为查询到的下一个节点
                        newNode.next = current
                        //插入节点的上一个节点指针为查询到的上一个节点
                        newNode.prev = current.prev
                        // 上一个节下一个指针=当前节点  
                        current.prev.next = newNode
                        //查询到的上一个节指针=插入的节点
                        current.prev = newNode
                    }
                    this.length += 1
                    return true
                }
            }

get (根据索引查询数据)

index 和 current 每次加1 当索引相等之后返回数据


            DoublyLinkedList.prototype.get = function (position) {
                if (position < 0 || position >= this.length) return null
                let current = this.head
                let inde = 0
                while (inde++ < position) {
                    current = current.next
                }
                return current.data
            }

indexof(获取索引)

index为索引 current为最开始的指针 遍历查询每次索引和指针加1 如果传入的data跟数据对应的 data相等 返回数据 没有匹配项返回-1

  • undefined   null  false  0  NaN  ""''(空字符串)转布尔为false
            DoublyLinkedList.prototype.indexOf = function (element) {
                // 1.定义变量, 保存信息
                let current = this.head
                let index = 0

                // 2.找到元素所在的位置
                while (current) {
                    if (current.element === element) {
                        return index
                    }
                    index++
                    current = current.next
                }

                // 3.来到这个位置, 说明没有找到, 则返回-1
                return -1
            }

update修改某个位置的元素

类似于get方法,找到指定元素修改启内容

 DoublyLinkedList.prototype.updata = function (position, data) {
                // 1.判断越界的问题
                if (position < 0 || position >= this.length) return false
                //寻找正确的节点
                let current = this.head
                let inde = 0
                while (inde++ < position) {
                    current = current.next
                }
                current.data = data
                return true

            }

removeAt方法(删除元素,根据索引)

情况一: 删除头部的元素

  • 删除头部的元素也分成两种情况.
  • 情况一: 链表只有一个元素, 那么将head/tail直接设置为null即可
  • 情况二: 链表有多个元素, 这个时候删除头部的元素. head = head.next. head.prev = null

情况二: 删除尾部的元素

  • 删除尾部的元素和删除头部有多个元素的情况比较相似. (也不需要考虑个数为1的情况, 因为上一种情况已经考虑了)
  • 将tail设置为tail的prev. tail的next设置为null即可.


情况三: 删除中间位置的元素

  • 这种情况就需要先找到正确的位置, 还是使用while循环.
  • 将previous的next直接设置成current的next, 将current.next的prev设置成previous即可

 

   DoublyLinkedList.prototype.removeAt = function (position) {
                if (position < 0 || position >= this.length) return null
                let current = this.head
                //判断是否只有一个节点
                if (this.length == 1) {
                    this.head = null
                    this.tail = null
                } else {
                    //判断是否删除的是第一个节点
                    if (position == 0) {
                        //第一个节点的下一个节点的prev引用
                        this.head.next.prev = null
                        // 将指向头部的指向第二个节点
                        this.head = this.head.next
                    } else if (position == this.length - 1) { //最后的节点
                        current = this.tail
                        // 最后一个节点的前一个节点的next引用赋值null
                        this.tail.prev.next = null
                        // 最后一个节点为前一个节点
                        this.tail = this.tail.prev
                    } else {
                        let index = 0
                        while (index++ < position) {
                            current = current.next
                        }
                        //查询到的上一个节点的next指针等于查询到的下一个节点
                        current.prev.next = current.next
                        //查询到的下一个节点的prev等于查询到的上一个节点
                        current.next.prev = current.prev
                    }
                    this.length -= 1
                }
                return current.data
            }
       

remove(删除数据,根据元素)

//获取data在列表中的数据,根据位置信息删除数据indexOf

  DoublyLinkedList.prototype.remove = function (element) {
                var index = this.indexOf(element)
                return this.removeAt(index)
            }

isEmpty&&size方法

         // 判断是否为空
            DoublyLinkedList.prototype.isEmpty = function () {
                return this.length === 0
            }

            // 获取链表长度
            DoublyLinkedList.prototype.size = function () {
                return this.length
            }

获取第一个元素&&获取最后一个元素

        // 获取第一个元素
            DoublyLinkedList.prototype.getHead = function () {
                return this.head.data
            }

            // 获取最后一个元素
            DoublyLinkedList.prototype.getTail = function () {
                return this.tail.data
            }

完整代码

单向

    function LinkedList() {
            //内部的类,节点类
            function Node(data) {
                this.data = data
                this.next = null
            }
            //属性
            this.haed = null//指针最开始
            this.length = 0
            // append 向列表尾部添加一个新的项
            LinkedList.prototype.append = function (data) {
                //创建新节点
                let newNode = new Node(data)
                //判断是否添加的是第一个节点
                if (this.length == 0) {//是第一个节点
                    this.haed = newNode
                } else {
                    //找到最后一个节点
                    let current = this.haed
                    while (current.next) {
                        current = current.next
                    }
                    //最后节点的next指向新节点
                    current.next = newNode
                }
                //长度加1
                this.length += 1
            }

            //toString方法
            LinkedList.prototype.toString = function () {
                //定义变量
                let current = this.haed
                let listString = ''
                //循环获取每一个节点
                while (current) {
                    listString += "," + current.data
                    current = current.next
                }
                return listString.slice(1)
            }

            // insert方法
            LinkedList.prototype.insert = function (position, data) {
                // 对position进行判断
                if (position < 0 || position > this.length) return false

                // 根据data创建newNode
                let newNode = new Node(data)

                // 判断插入的位置是否为第一个
                if (position == 0) {
                    //把指针赋值给新节点,在把指针修改为新节点的指针
                    newNode.next = this.haed
                    this.haed = newNode
                } else {
                    let index = 0
                    let previous = null
                    let current = this.haed
                    while (index++ < position) {
                        previous = current
                        current = current.next
                    }
                    newNode.next = current
                    previous.next = newNode
                }
                //长度加1
                this.length += 1
                return true
            }

            // get方法
            LinkedList.prototype.get = function (position) {
                //越界判断
                if (position < 0 || position >= this.length) return null
                //获取对应的data
                let current = this.haed
                let index = 0
                //position=2
                // index = 0 current=下一个指针
                // index = 1 current=下一个指针
                // index = 2 current=数据
                while (index < position) {
                    index++
                    current = current.next
                }
                return current.data
            }

            // inexof方法
            LinkedList.prototype.inexOf = function (data) {
                // 定义变量
                let current = this.haed
                let index = 0
                //开始查找
                while (current) {
                    if (current.data == data) {
                        return index
                    }
                    current = current.next
                    index += 1
                }
                return -1
            }

            //update
            LinkedList.prototype.update = function (position, element) {
                //越界判断
                if (position < 0 || position >= this.length) return false
                //查找正确的节点
                let current = this.haed
                let index = 0
                while (index < position) {
                    index++
                    current = current.next
                }
                // 将position位置的node的data改为newdata
                current.data = element
                return true
            }

            //removeAt
            LinkedList.prototype.removeAt = function (position) {
                if (position < 0 || position >= this.length) return null
                let current = this.haed
                //判断是否删除的为第一个节点
                if (position == 0) {
                    this.haed = this.haed.next
                } else {
                    let index = 0
                    let previous = null//前一个节点
                    while (index++ < position) {
                        previous = current
                        current = current.next
                    }
                    //前一个节点的next指向,current的next
                    previous.next = current.next
                }
                this.length -= 1
                return current.data
            }

            // remove
            LinkedList.prototype.remove = function (data) {
                //获取data在列表中的数据
                let position = this.inexOf(data)
                //根据位置信息删除数据
                return this.removeAt(position)
            }
            LinkedList.prototype.isEmpty = function (data) {
                return this.length == 0
            }
            LinkedList.prototype.size = function () {
                return this.length
            }
        }
     

双向

    function DoublyLinkedList() {
            // 内置类:节点类
            function Node(data) {
                this.data = data
                this.next = null
                this.prev = null // 新添加的
            }
            //属性
            this.head = null
            this.tail = null
            this.length = 0
            // 定义相关操作方法
            // 在尾部追加数据
            DoublyLinkedList.prototype.append = function (element) {
                // 1.根据元素创建节点
                var newNode = new Node(element)

                // 2.判断列表是否为空列表
                if (this.head == null) {
                    this.head = newNode
                    this.tail = newNode
                } else {
                    this.tail.next = newNode
                    newNode.prev = this.tail
                    this.tail = newNode
                }

                // 3.length+1
                this.length++
            }

            // 正向遍历的方法
            DoublyLinkedList.prototype.forwardString = function () {
                //定义变量
                let current = this.head
                let forwardStr = ''

                // 依次向后遍历获取每一个节点
                while (current) {
                    forwardStr += "," + current.data
                    current = current.next
                }

                return forwardStr.slice(1)
            }

            // 反向遍历的方法
            DoublyLinkedList.prototype.reverseString = function () {
                var current = this.tail
                var reverseStr = ""
                // 依次向前遍历获取每一个节点
                while (current) {
                    reverseStr += "," + current.data
                    current = current.prev
                }

                return reverseStr.slice(1)
            }

            // 实现toString方法
            DoublyLinkedList.prototype.toString = function () {
                return this.forwardString()
            }

            // insert方法
            DoublyLinkedList.prototype.insert = function (position, element) {
                // 1.判断越界的问题
                if (position < 0 || position > this.length) return false
                //根据data创建新节点
                var newNode = new Node(element)
                //判断列表是否为空
                if (this.length == 0) {
                    this.head = newNode
                    this.tail = newNode
                } else {
                    //判断position是否为0
                    if (position == 0) {//第一个节点
                        //原来的第一个节点的prev=指向改变之后的第一个节点
                        this.head.prev = newNode
                        // 插入节点的下一个节点是当前节点
                        newNode.next = this.head
                        // 改变头部的节点为新插入的节点
                        this.head = newNode
                    } else if (position == this.length) {//最后一个节点
                        //新节点的前一个节点,等于最后一个节点
                        newNode.prev = this.tail
                        //原来的最后一个节点=插入的节点
                        this.tail.next = newNode
                        //改变指向尾部的节点为新节点
                        this.tail = newNode
                    } else {//其他情况
                        let current = this.head
                        let index = 0
                        while (index++ < position) {
                            current = current.next
                        }
                        //插入节点的下一个节点指针为查询到的下一个节点
                        newNode.next = current
                        //插入节点的上一个节点指针为查询到的上一个节点
                        newNode.prev = current.prev
                        // 上一个节下一个指针=当前节点  
                        current.prev.next = newNode
                        //查询到的上一个节指针=插入的节点
                        current.prev = newNode
                    }
                    this.length += 1
                    return true
                }
            }

            DoublyLinkedList.prototype.get = function (position) {
                if (position < 0 || position >= this.length) return null
                let current = this.head
                let inde = 0
                while (inde++ < position) {
                    current = current.next
                }
                return current.data
            }

            // 根据元素获取链表中的位置
            DoublyLinkedList.prototype.indexOf = function (element) {
                // 1.定义变量, 保存信息
                let current = this.head
                let index = 0

                // 2.找到元素所在的位置
                while (current) {
                    if (current.element === element) {
                        return index
                    }
                    index++
                    current = current.next
                }

                // 3.来到这个位置, 说明没有找到, 则返回-1
                return -1
            }

            DoublyLinkedList.prototype.updata = function (position, data) {
                // 1.判断越界的问题
                if (position < 0 || position >= this.length) return false
                //寻找正确的节点
                let current = this.head
                let inde = 0
                while (inde++ < position) {
                    current = current.next
                }
                current.data = data
                return true

            }

            DoublyLinkedList.prototype.removeAt = function (position) {
                if (position < 0 || position >= this.length) return null
                let current = this.head
                //判断是否只有一个节点
                if (this.length == 1) {
                    this.head = null
                    this.tail = null
                } else {
                    //判断是否删除的是第一个节点
                    if (position == 0) {
                        //第一个节点的下一个节点的prev引用
                        this.head.next.prev = null
                        // 将指向头部的指向第二个节点
                        this.head = this.head.next
                    } else if (position == this.length - 1) { //最后的节点
                        current = this.tail
                        // 最后一个节点的前一个节点的next引用赋值null
                        this.tail.prev.next = null
                        // 最后一个节点为前一个节点
                        this.tail = this.tail.prev
                    } else {
                        let index = 0
                        while (index++ < position) {
                            current = current.next
                        }
                        //查询到的上一个节点的next指针等于查询到的下一个节点
                        current.prev.next = current.next
                        //查询到的下一个节点的prev等于查询到的上一个节点
                        current.next.prev = current.prev
                    }
                    this.length -= 1
                }
                return current.data
            }

            // 根据元素删除
            DoublyLinkedList.prototype.remove = function (element) {
                var index = this.indexOf(element)
                return this.removeAt(index)
            }
        }

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

数据结构---链表 的相关文章

  • CTF之逆向入门

    逆向工程 Reverse Engineering 又称反向工程 是一种技术过程 即对一项目标产品进行逆向分析及研究 从而演绎并得出该产品的处理流程 组织结构 功能性能规格等设计要素 以制作出功能相近 但又不完全一样的产品 逆向工程源于商业及
  • 如何给 unplugin-vue-components/vite 写一个简单的 resolver

    大部分工作 unplugin vue components 都已经处理好了 我们只需要接收组件名来判断是否是自己的组件 然后处理对应的导入逻辑 一共 3 个字段 as 重命名类似 import componentNameReName fro
  • Web 安全漏洞之 OS 命令注入

    什么是 OS 命令注入 上周我们分享了一篇 Web 安全漏洞之 SQL 注入 其原理简单来说就是因为 SQL 是一种结构化字符串语言 攻击者利用可以随意构造语句的漏洞构造了开发者意料之外的语句 而今天要讲的 OS 命令注入其实原理和 SQL
  • WEB前端常见受攻击方式及解决办法总结

    一个网址建立后 如果不注意安全问题 就很容易被人攻击 下面讨论一下集中漏洞情况和放置攻击的方法 一 SQL注入 所谓的SQL注入 就是通过把SQL命令插入到web表单提交或输入域名或页面请求的查询字符串 最终达到欺骗服务器执行恶意的SQL命
  • WEB前端常见受攻击方式及解决办法总结

    一个网址建立后 如果不注意安全问题 就很容易被人攻击 下面讨论一下集中漏洞情况和放置攻击的方法 一 SQL注入 所谓的SQL注入 就是通过把SQL命令插入到web表单提交或输入域名或页面请求的查询字符串 最终达到欺骗服务器执行恶意的SQL命
  • 每天10个前端小知识 <Day 6>

    前端面试基础知识题 1 使用js实现二分查找 二分查找 也称为折半查找 是指在有序的数组里找出指定的值 返回该值在数组中的索引 查找步骤如下 从有序数组的最中间元素开始查找 如果该元素正好是指定查找的值 则查找过程结束 否则进行下一步 如果
  • Android SDK开发艺术探索(五)安全与校验

    一 前言 本篇是Android SDK开发艺术探索系列的第五篇文章 介绍了一些SDK开发中安全方面的知识 包括资源完整性 存储安全 权限校验 传输安全 代码混淆等知识 通过基础的安全配置为SDK保驾护航 探索SDK开发在安全方面的最佳实践
  • 链表的中间节点

    链表的中间节点 力扣 LeetCode 官网 全球极客挚爱的技术成长平台 备战技术面试 力扣提供海量技术面试资源 帮助你高效提升编程技能 轻松拿下世界 IT 名企 Dream Offer https leetcode cn problems
  • 基于java的饮食分享平台系统设计与实现

    基于java的饮食分享平台系统设计与实现 I 引言 A 研究背景和动机 近年来 随着人们生活水平的提高和健康意识的增强 饮食健康已经成为越来越多人的关注焦点 因此 一个方便快捷的饮食分享平台就显得尤为重要 基于Java的饮食分享平台系统设计
  • 矩阵基本操作3

    题目描述 问题描述 定义一个N M N M lt 100 的矩阵 将一个该矩阵的行和列的元素互换 存到另一个二维数组中 输入格式 一行两个整数 N M 中间用空格隔开 表示矩阵有N行 M列 接下来共N行M列表示矩阵 输出格式 输出转置以后的
  • 探索Web开发的未来——使用KendoReact服务器组件

    Kendo UI 是带有jQuery Angular React和Vue库的JavaScript UI组件的最终集合 无论选择哪种JavaScript框架 都可以快速构建高性能响应式Web应用程序 通过可自定义的UI组件 Kendo UI可
  • 低代码-详情页组件设计

    效果图 详情页数据结构定义 layout 按钮数据 buttonLayout headButton 页头按钮 footButton 页脚按钮 详情页表单配置 config 配置组件列表 detailLayout 默认行为 进表单初始化 只展
  • 低代码配置-属性配置面板设计

    模块设计 tab项切换 组件基础属性 组件数据属性 组件事件属性 表单属性 模块输出函数设计 tab切换函数 列表表单属性 数据来源 调用接口时一次赋予 无需使用selectItem 如需使用 归入基础属性 列表标题 是否展示筛选区域
  • 顺序表和链表基础

    定义动态的顺序表 typedef int SLDataType typedef struct Seqlist SLDataType array size t size size t capacity Seqlist 在顺序表中插入数据 bo
  • chrome浏览器无法在地址栏输入内容搜索问题解决--图文

    关于日常遇到的小问题解决记录一下 1 导航栏录入信息后跳转错误 2 解决办法 默认百度搜索引擎地址错误 百度正确的搜索格式是 http www baidu com s wd s chrome浏览器中百度的搜索格式是 http www bai
  • 「优选算法刷题」:移动零

    嗨 这个假期罗根开始接触了算法 在为今年的蓝桥杯做准备 所以 开个新专栏 记录记录自己做算法题时的心得 一 题目 给定一个数组 nums 编写一个函数将所有 0 移动到数组的末尾 同时保持非零元素的相对顺序 请注意 必须在不复制数组的情况下
  • 用栈实现队列(OJ中报错的处理)

    用栈实现队列 ERROR AddressSanitizer myQueueFree函数中栈的释放处现了问题 没有调用StackDestory而是直接free了 这个是栈初始化时 capacity与malloc申请的空间大小没有匹配 请你仅使
  • 每天10个前端小知识 <Day 14>

    前端面试基础知识题 1 CSSOM树和DOM树是同时解析的吗 浏览器会下载HTML解析页面生成DOM树 遇到CSS标签就开始解析CSS 这个过程不会阻塞 但是如果遇到了JS脚本 此时假如CSSOM还没有构建完 需要等待CSSOM构建完 再去
  • 高精度运算合集,加减乘除,快速幂,详细代码,OJ链接

    文章目录 零 前言 一 加法 高精度加法步骤 P1601 A B 二 减法 高精度减法步骤
  • 获取年与年之间的所有年份

    function getYearsBetween startYear endYear var years 存放结果的数组 for var year startYear year lt endYear year years push year

随机推荐

  • tcp三次握手和四次挥手的过程

    TCP是面向连接的 无论哪一方向另一方发送数据之前 都必须先在双方之间建立一条连接 在TCP IP协议中 TCP 协议提供可靠的连接服务 连接是通过三次握手进行初始化的 三次握手的目的是同步连接双方的序列号和确认号 并交换 TCP窗口大小信
  • 简述JAVA集合框架

    简述JAVA集合框架 对常用的数据结构和算法做了一些接口和具体实现接口的类 所有抽象出来的数据结构统称为Java集合框架 在具体应用时 不必考虑数据结构和算法实现细节 只需要用这些类创建出来一些对象 然后直接应用就可以了 这样就大大提高了编
  • Nginx中代理的上下文路径设置

    Nginx中代理的上下文路径设置 实际配置nginx的时候 在Location段中配置的路径 request uri 以及代理指令 proxy pass 中设置的上下文路径的组合不同 最后实现的结果就不一样 例子 加入请求nginx服务的U
  • php修改学生信息代码_简单学习PHP中的层次性能分析器

    在 PHP 中 我们需要进行调试的时候 一般都会使用 memory get usage 看下内存的使用情况 但如果想看当前的脚本 CPU 的占用情况就没有什么现成的函数了 不过 PHP 也为我们提供了一个扩展 XHProf 这是由 Face
  • 24.qint64转QString 以及获取文件属性

    qint64转QString 1 qint64 size info size 2 qint64 转QString 3 QString size2 tr 1 arg size 获取文件属性 1 include mainwindow h 2 i
  • 大数据与人工智能的关系

    大数据与人工智能有密切的关系 大数据可以为人工智能提供大量的训练数据 从而提高人工智能的准确性和效率 人工智能又可以帮助我们对大数据进行分析和挖掘 提取有用的信息
  • 计算机二级python经典真题

    计算机二级python经典考题 1 键盘输入正整数n 按要求把n输出到屏幕 格式要求 宽度为20个字符 减号字符 右填充 右对齐 带千位分隔符 如果输入正整数超过20位 则按照真实长度输出 例如 键盘输入正整数n为1234 屏幕输出 1 2
  • Android监听屏幕录制的过程

    Android监听屏幕录制的过程如下 在AndroidManifest xml文件中声明屏幕录制权限
  • Bert和T5的区别

    Bert 和 T5 之间的主要区别在于预测中使用的标记 单词 的大小 Bert 预测一个由单个词组成的目标 single token masking 另一方面 T5 可以预测多个词 如上图所示 它在学习模型结构方面为模型提供了灵活性 Tra
  • Vue中如何进行数据可视化大屏展示

    Vue中如何进行数据可视化大屏展示 在现代数据驱动的应用程序中 数据可视化大屏已经成为了非常重要的一环 通过对海量数据进行可视化展示 可以帮助用户更好地理解和分析数据 从而做出更加明智的决策 在Vue中进行数据可视化大屏展示也变得越来越流行
  • JVM 运行时数据区(栈和堆)

    文章目录 JVM 是一种规范 什么是 JVM 为什么 JVM 是一种规范 Java 程序的执行过程 JVM 与字节码文件 栈指令集架构和寄存器指令集架构 Hotspot 虚拟机及 Dalvik ART 虚拟机 JVM 的组成部分及架构 运行
  • Postman Windows7可用最大版本

    https dl pstmn io download version 7 2 2 win64
  • 搭建DAO层和Service层代码

    第一部分建立实体和映射文件 1 通过数据库生成的实体 此步骤跳过 关于如何查看生成反向工程实体类查看SSH框架搭建教程 反向工程章节 Tmenu和AbstractorTmenu是按照数据库表反向工程形成的JAVA实体 在形成实体的时候注意
  • python:编写程序,输入一批学生的成绩,求平均成绩和最高分。

    n 1 max score 0 score sum 0 while n lt 6 n 1 student Id input 请输入编号 编号输入 score eval input 请输入成绩 成绩输入 score sum score 输入成
  • 新机部署docker报错docker.service: Start request repeated too quickly.

    报错内容 主要报错内容 docker service Start request repeated too quickly Failed with result exit code Failed to start Docker Applic
  • 中国XXXXXXXXXXXXX管理软件销售实施三部曲

    中国XXXXXXXXXXXXX牛B 管理软件销售实施服务一条龙分三部分走 第一步 卖软件 客户的艳阳天 卖软件前 销售的嘴巴像屁股绽放般 见过狗没 没见过的话 只能在签约前才能见到的 客户你说想实现啥 这个牛B的中国XXXXXXXXXXXX
  • VSCode安装教程

    VSCode软件下载 官网下载地址 Visual Studio Code Code Editing Redefined 1 点击Download for Windows的下拉按钮 点击Other downloads 2 在这里可以选择自己想
  • 小孩机器人编程真的有用吗

    小孩机器人编程真的有用吗 很多的家长在培养孩子的学习的时候 是十分的认真耐心的 他们会给孩子选择一些能够有利于孩子成长的课程 就拿现在很多的家长想要孩子去学习机器人编程的课程来说 有的家长对于小孩机器人编程真的有用吗并不是很清楚 今天我们就
  • Docker(六)----Swarm搭建Docker集群

    一 什么是Swarm Swarm这个项目名称特别贴切 在Wiki的解释中 Swarm behavior是指动物的群集行为 比如我们常见的蜂群 鱼群 秋天往南飞的雁群都可以称作Swarm behavior Swarm项目正是这样 通过把多个D
  • 数据结构---链表

    目录 链表的概念 封装单项链表 封装链表结构 append方法 追加元素 toString方法 转字符串 insert方法 插入元素 get方法 获取元素 indexof 获取索引 update修改某个位置的元素 removeAt方法 删除