数组和链表的区别及JS转换

本文详细介绍了数组和链表的定义、优缺点,强调了它们在数据插入和删除操作上的差异。并探讨了在JavaScript中如何实现链表,包括单向链表、双向链表和循环链表。最后,讨论了如何在JS中将数组转换为链表以及将链表转换回数组。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、数组

1.1 数组的定义

数组是若干个元素按照顺序排列存放的一个集合,并且每个元素至少存在一个 索引(index) 或者 关键字(key) 所标识,每个元素的位置都可以通过计算索引拿到。

一维数组:[1,2,3]; //数组的每一个元素是一个数据类型

二维数组:[["a","b","c"],[1,2,3],123]; //数组的每一个元素是一个一维数组

三维数组:[[["a","b","c"],[1,2,3]],[["a","b","c"],[1,2,3]]]; //数组的每一个元素是一个二维数组

1.2数组的优缺点

数组作为我们工作中最为常见的一种数据结构,其最大的特性莫过于高效的 查询 数据;

但是其缺点也是非常的明显,在进行 插入 和 删除 数据时,需要进行大量的数据移动补位消耗大量的时间。

 

2、链表

2.1 链表的定义

链表结构其实是内存内部的一种存储方式,链表则是把一系列节点串联起来,每个节点上至少包含两个部分: 数据域 与 指针域。

数据:保存数据;

指针:指向下一个节点的引用;

链表中的每个节点,通过指针域的值,形成一个线性结构。

其中,data中保存着数据,next保存着下一个链表的引用。

我们说 data2 跟在 data1 后面,而不是说 data2 是链表中的第二个元素。

我们将链表的尾元素指向了 null 节点,表示链接结束的位置。

 

由于链表的起始点的确定比较麻烦,因此很多链表的实现都会在链表的最前面添加一个特殊的节点,称为 头节点,表示链表的头部。

 

 向链表中插入一个节点的效率很高,需要修改它前面的节点(前驱),使其指向新加入的节点,而将新节点指向原来前驱节点指向的节点即可。下面我将用图片演示如何在 data2 节点 后面插入 data4 节点。

 从链表中删除一个节点,也很简单。只需将待删节点的前驱节点指向待删节点的,同时将待删节点指向null,那么节点就删除成功了。

2.2 链表的优缺点

因为链表是一种 松散 的结构体,所以当你想要找到其中的某一个节点时,只能够从 头节点 一级一级的往下找,但也因为这种松散的结构使得其进行 插入删除 时只需要改变其 指针域 的指向即可

优点:适合动态插入和删除的应用场景;

缺点:不能快速的定位和随机访问数据。

3、数组和链表的对比

  • 数组和链表都是线性数据结构
  • 数组为静态结构,静态分配内存。链表支持动态分配内存
  • 数组在数据储存时是一段连续的内存空间,链表是非连续的通过指针来串联
  • 数组可以根据下标定位快速查找,链表则需要遍历查找
  • 数组在插入和删除时会有大量的数据移动补位,链表只需要改变指针指向

4、JS中链表的实现

不同于new Array()new Set()new Map()等数据结构,目前js官方还没有为我们提供一个直接的链表API实现。不过我们可以通过对象的方式去模拟出一个链表

链表可以分为三类:

  • 单向链表:线型数据结构,指针指向下一个节点,终点指向null
  • 双向链表:可以往前或者往后添加节点,指针指向前一个节点和后一个节点
  • 循环链表:循环链表的第一个节点指向最后一个节点,最后一个节点指向第一个节点(循环链表又可以划分为 “单向循环链表”和“双向循环链表”)
// 链表对象化,便于理解
const obj = {
  data: 1,
  next: {
    data: 2,
    next: {
      data: 3,
      next: null,
    },
  },
};

5、使用js实现将数组转为链表,及将链表转为数组

5.1 数组转链表

    function arrayList(arr) {
        if (arr.length === 0) {
            return null
        }
        var nodes = []

        for (var i = 0; i < arr.length; i++) {
            var node = {}
            node.value = arr[i]
            node.next = null
            nodes.push(node)
        }

        for (var i = 0; i < nodes.length - 1; i++) {
            nodes[i].next = nodes[i + 1]
        }

        return nodes[0]
    }
//不占用额外空间
    function arrayList(arr) {
        if (!arr.length) {
            return null
        }

        let node;
        let head = {
            value: arr[0],
            next: null
        }
        let preNode = head //preNode变量用来保存前一个节点

        for (let i = 1; i < arr.length; i++) {
            node = {
                value: arr[i],
                next: null
            }
            preNode.next = node //将前一个节点的next指向当前节点
            preNode = node //将node赋值给preNode
        }

        return head
    }
//递归
    function arrayList(ary, start = 0) {
        if (start === ary.length) {
            return null
        }

        var node = {
            value: ary[start],
            next: null
        }

        var rest = arrayList(ary, start + 1)
        node.next = rest
        return node
    }

 5.2 链表转数组

    function listArray(head) {
        if (!head) {
            return []
        }

        var result = []
        var p = head

        while (p) {
            result.push(p.value)
            p = p.next
        }

        return result
    }

 

    function listArray(head) {
        if (!head) {
            return []
        }
        var result = [head.value]
        var restValues = list2array(head.next)
        return result.concat(restValues)
    }

 参考文章

JS中的算法与数据结构——链表(Linked-list)

JS中的数据结构——链表(Linked-list)详解

使用js实现将数组转为链表,及将链表转为数组。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值