Javascript常见数据结构三——链表

本文介绍了JavaScript中链表和双向链表的基本原理,包括如何创建链表结构,实现append、find、insert、remove和print等操作,以及双向链表的高效插入和删除。重点讨论了链表在大数据场景中的优势和双向链表的开发效率提升。
摘要由CSDN通过智能技术生成

Javascript常见数据结构三——链表

四、链表

1.创建链表结构

当我们使用的数组数据量比较大的时候 ,我们往数组前面插入一个数据,在这之后的所有元素的索引都要向后挪,这个时候,效率是很低的。

链表 很好的解决了这个问题 链表中的所有数据只与他的下一个数据有关。执行插入操作的时候,无论数据量有多少,我们只需要断开链子,将新插入的元素与插入位置的两端的元素连接起来就可以了

适用于:当数据比较庞大的时候,并且需要多次执行插入操作 此时选择链表 性能会高于数组

功能需求分析:

 添加节点 append
 查找结点 find
 指定数据后面添加节点 insert
 移除指定数据对应的节点 remove
 打印所有数据 print
 返回链表长度 size
let LinkedList = (function () {
    // Node 用来存储数据和下一个节点
    class Node {
        constructor(data) {
            this.data = data
            this.next = null
        }
    }

    // Symbol 解决外界访问
    let HEAD = Symbol()
    return class {
        constructor() {
            this[HEAD] = null
        }

        // 添加数据
        append(data) {
            let node = new Node(data)
            let head = this[HEAD]
            // 如果 链表头部为空
            if (!head) {
                this[HEAD] = node
                return
            }
            // 如果链表头部不为空 需要找到链表尾部 将数据插入进去
            // 新数据添加到链表尾部
            while (head.next) {
                head = head.next
            }
            head.next = node
        }

        // 查找结点
        find(index) {
            let head = this[HEAD]
            let i = 0
            while (head) {
                if (i === index) {
                    return head
                }
                head = head.next
                i++
            }
            return null
        }

        // 指定数据插入
        insertByData(data, newData) {
            // 找到链表头部
            let head = this[HEAD]
            // 新数据
            let node = new Node(newData)
            // 找到 data 对应的数据
            let thisNode
            while (head && head.data !== data) {
                head = head.next
            }
            // 如果找不到 data 对应的数据
            if (!head) {
                // 找不到对应的数据
                console.warn('当前链表不存在对应的数据')
                return
            }
            // 得到 next 之后 需要断开head和 next的链条 然后插入新数据
            let next = head.next
            head.next = node
            node.next = next
        }

        // 指定数据移除
        removeByData(data){
            let head = this[HEAD]
            while(head && head.next){
                // 寻找指定的data数据
                if(head.next.data === data){
                  return  head.next = head.next.next
                }
                // 移步到下一个数据
                head = head.next
            }
        }

        // 指定序号插入
        insertById(index,newData){
            // 待插入的节点
            let node = new Node(newData)
            // 找到当前序号对应的节点
            let nodeAfter = this.find(index)
            // 找到序号对应的前一个节点
            let nodeBefore
            if(index === 0){
                // index 是 0
                this[HEAD] = node
            }else{
                // index 不是0
                nodeBefore = this.find(index-1)
                if(!nodeBefore){
                    console.warn("指定索引超出链表长度")
                    return
                }
                nodeBefore.next = node
            }
            node.next = nodeAfter
        }

        // 指定序号移除
        remove(index){
            let thisNode = this.find(index)
            if(index===0){
                this[HEAD] = thisNode.next
            }else{
                let NodeBefore = this.find(index-1)
                // 判断NodeBefore 是否存在 不存在则是超出了当前链表长度
                if(!NodeBefore){
                    console.warn('指定索引超出链表长度')
                    return
                }
                NodeBefore && (NodeBefore.next = thisNode.next)
            }
        }

        // 打印数据
        print() {
            let head = this[HEAD]
            let arr = []
            while (head) {
                arr.push(head.data)
                head = head.next
            }
            // 返回值有多种形式 在这里 我就返回一个数组
            return arr
        }

        // 链表长度
        size(){
            let size = 0
            let head = this[HEAD]
            while(head){
                head = head.next
                size++
            }
            return size
        }
    }
})()

2.双向链表

双向链表的开发效率会优于链表,也是比较常用的一种数据结构。
双向链表在链表的基础上进行了优化,每个节点可以拿到当前节点的前后两个节点,插入操作不需要在进行循环遍历,极大的提高了性能,我们平时使用的也比较多
let LinkedList = (function () {
    class Node {
        constructor(data, linked) {
            this.data = data
            this.linked = linked
            this.next = null
            this.prev = null
        }
        // 当前数据之前插入数据
        insertBefore(data) {
            let prev = this.prev
          //  console.log('前一个节点为:', prev)
          //  console.log('this', this)
            let node = new Node(data, this.linked)
            if (prev) {
                // 前一个存在
               // console.log('前一个节点存在')
                prev.next = node
                node.prev = prev
            } else {
                // 前一个不存在  说明当前节点为头节点
              //  console.log('前一个节点不存在')
                this.linked[HEAD] = node
            }
            this.prev = node
            node.next = this

            this.linked.length++
            return node
        }

        // 当前数据之后插入数据
        insertAfter(data) {
            let next = this.next
            let node = new Node(data, this.linked)
            if (next) {
                // 后一个节点存在
                node.next = next
                next.prev = node
            } else {
                // 后一个节点不存在 说明当前节点为为节点
                this.linked[FOOT] = node
            }
            this.next = node
            node.prev = this
            // 插入成功后 length ++
            this.linked.length++
            return node
        }

        // 删除当前数据
        remove(){
            let prev = this.prev
            let next = this.next
            // 如果prev 不存在 那么this链表头部
            if(!prev){
                this.linked[HEAD] = next
            }
            // 如果next不存在 那么this为链表尾部
            if(!next){
                this.linked[FOOT] = prev
            }
            prev && (prev.next = next)
            next && (next.prev = prev)
            this.linked.length--
        }
    }
    // 定义 头部 尾部 标记
    // 暴露给外界 但是不可以进行操作
    const HEAD = Symbol('head')
    const FOOT = Symbol('foot')
    return class {
        constructor() {
            this[HEAD] = null
            this[FOOT] = null
            this.length = 0
        }
        // 链表添加数据
        append(data) {
            let node = new Node(data, this)
            if (this[FOOT]) {
                this[FOOT].next = node
                node.prev = this[FOOT]
                this[FOOT] = node
            } else {
                this[HEAD] = node
            }
            this[FOOT] = node
            this.length ++
            return node
        }
        // 查询链表数据
        print(){
            let head = this[HEAD]
            let arr = []
            while(head){
                arr.push(head.data)
                head = head.next
            }
            return arr
        }
    }
})()
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

貂蝉的腿毛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值