javascript链表_使用javascript的链表初学者指南

javascript链表

了解链接列表(Understanding Linked Lists)

Even as a beginner user of JavaScript, chances are you have come across data structures like arrays, strings and objects. You may or may not have known that these are referred to as “data structures”, and the term may be a bit confusing. Worry not! In this article, I will explain what a data structure is, and will show you how to implement a custom data structure in JavaScript: a linked list. I will also talk about why you would choose to use this data structure over others.

即使是JavaScript的初学者,也有可能遇到过数组,字符串和对象等数据结构。 您可能知道也可能不知道这些被称为“数据结构”,并且该术语可能会有些混乱。 不用担心! 在本文中,我将解释什么是数据结构,并向您展示如何在JavaScript中实现自定义数据结构:链接列表。 我还将讨论为什么您会选择在其他数据结构上使用此数据结构。

First things first, data what?

首先,数据是什么?

So, what is a data structure? Simply put, a data structure refers to a collection of data and how we can operate on such data. We can refer to four fundamental operations: access, insertion, deletion and search.

那么,什么是数据结构? 简而言之,数据结构是指数据的集合以及我们如何对这些数据进行操作。 我们可以参考四个基本操作:访问,插入,删除和搜索。

Let’s use arrays as an example to understand this, as arrays are a simple data structure present in virtually every programming language. Note that the particular internal representation of arrays can vary between different programming languages, but this provides a general overview.

让我们以数组为例来理解这一点,因为数组实际上是每种编程语言中都存在的简单数据结构。 请注意,数组的特定内部表示在不同的编程语言之间可能会有所不同,但这提供了一般概述。

Arrays are structures that store a sequence of data. We can access (and update) the data using bracket notation: myArray[index]. We can add and remove elements from the back using push() and pop(), respectively. We can also add and remove elements at the front using shift() and unshift(), respectively, or in the middle using splice(). We can search using find(). The specifics of how JavaScript performs these operations is not in the scope of this article, but an important thing to keep in mind is this: some operations take longer than others.

数组是 存储数据序列的结构 我们可以使用括号符号myArray [index]访问(和更新)数据。 我们可以分别使用push()和pop()从背面添加和删除元素。 我们还可以分别在前面使用shift()和unshift()或在中间使用splice()添加和删除元素。 我们可以使用find()进行搜索。 JavaScript如何执行这些操作的细节不在本文的讨论范围之内,但是要记住的一件重要事情是:某些操作要比其他操作花费更长的时间。

For example, we can get the first item of the array very easily. But what if we wanted to add or delete an item at the beginning of the array? Even though this is just one function call away, the indices of every item in the array would have to change, so this operation would be more expensive in terms of computation (check this Wikipedia entry out to learn more). What if we need to regularly add and delete items from the front of the array? Could we do it more efficiently? The answer is yes!

例如,我们可以很容易地获得数组的第一项。 但是,如果我们想在数组的开头添加或删除项目怎么办? 即使这只是一个函数调用,数组中每个项目的索引也必须更改,因此,此操作在计算方面将更加昂贵(请参阅Wikipedia条目以了解更多信息)。 如果我们需要定期从阵列的前面添加和删除项目怎么办? 我们可以更有效地做到吗? 答案是肯定的!

Enter Linked Lists

输入链接列表

Linked lists are a data structure made up of nodes. A node is simply a structure composed of some data and one or more pointers. A pointer is just a reference to another node. So now instead of an indexed collection of data (an array), we have a bunch of data where each item has a link to the next one. We refer to the first item of a linked list as the head and the last item as the tail.

链表是由节点组成的数据结构。 节点只是一种由一些数据和一个或多个指针组成的结构。 指针只是对另一个节点的引用。 因此,现在有了一堆数据,而不是索引数据集(一个数组),其中每一项都有指向下一项的链接。 我们将链接列表的第一项称为标题,将最后一项称为 尾巴

I will show you two types of linked lists: singly and doubly linked lists. The general concept of both is the same, there is really just one difference: each node in a singly linked list contains a pointer to the next node in the list, while each node in a doubly linked list contains a pointer to the next node and a pointer to the previous node in the list.

我将向您展示两种类型的链表:单链表和双链表。 两者的一般概念是相同的,实际上只有一个区别:单链接列表中的每个节点都包含指向列表中下一个节点的指针,而双链接列表中的每个节点都包含指向下一个节点的指针,并且指向列表中上一个节点的指针。

单链表 (Singly Linked Lists)

Diagram of a singly linked list
https://commons.wikimedia.org/w/index.php?curid=2245162 https: //commons.wikimedia.org/w/index.php?curid = 2245162

Let’s implement a linked list with some basic functionality. To begin our implementation of a singly linked list let’s define our ListNode and our SinglyLinkedList classes:

让我们用一些基本功能实现一个链表。 要开始实现单链列表,让我们定义ListNode和SinglyLinkedList类:

Image for post
ListNode and SinglyLinkedList class definitions
ListNode和SinglyLinkedList类定义

When we initialize our list, the head is null because we have no data, and we keep track of the size of our list. Think of how we would calculate the size of our list if we didn’t keep track of the size within our list.

初始化列表时,标头为null,因为我们没有数据,并且会跟踪列表的大小。 想想如果不跟踪列表中的大小,我们将如何计算列表的大小。

Now we are ready to add some data to our list. Let’s implement the function insertAtHead:

现在我们准备将一些数据添加到列表中。 让我们实现功能insertAtHead:

Image for post
insertAtHead function
insertAtHead函数

We first create a ListNode with our data. This newNode will be the new head of our list. If the list was empty before, we are done. If there were elements in the list, we need to make sure that the new head points to the old head. Finally, we increment the size of our list.

我们首先使用数据创建一个ListNode。 这个newNode将成为我们列表的新头。 如果列表以前是空的,那么我们就完成了。 如果列表中有元素,我们需要确保新头指向旧头。 最后,我们增加列表的大小。

Let’s tackle the deletion problem now. Let’s remove the head of a list.

让我们现在解决删除问题。 让我们删除列表的标题。

Image for post
removeHead function
removeHead函数

We first check if there are actually any elements in the list. If we indeed have elements, the next pointer of our current head will become the new head. And let’s not forget to decrement the size of our list.

我们首先检查列表中是否确实有任何元素。 如果我们确实有元素,那么当前头的下一个指针将成为新头。 而且,不要忘了减少列表的大小。

Let’s think about how we can find an element somewhere in the middle of the array and delete it. We will need to find the element by its value, and keep track and the node right before. Once we find the element we want to remove, we can just update the pointer on the previous element, and decrement our size variable.

让我们考虑一下如何在数组中间的某个位置找到一个元素并将其删除。 我们将需要通过元素的值查找元素,并保持跟踪和紧接其前的节点。 找到要删除的元素后,就可以更新前一个元素上的指针,并减小size变量。

Image for post
deleteByValue function
deleteByValue函数

Feel free to play with the singly linked list in this CodePen.

随意使用此CodePen中的单链接列表。

What if instead of inserting a node at the end, we wanted to remove the last node? With a reference to the tail, we can insert a new node because we can simply update the old tail’s pointer. But if we wanted to delete the tail, we would need access to the node immediately before it.

如果我们要删除最后一个节点,而不是在最后插入节点怎么办? 引用尾巴,我们可以插入一个新节点,因为我们可以简单地更新旧尾巴的指针。 但是,如果要删除尾部,则需要在其之前立即访问该节点。

输入双链表 (Enter Doubly Linked Lists)

So what if every node contained a reference to both the previous node and the next node? Now we can insert and delete at both the head and the tail without any traversal.

那么,如果每个节点都包含对上一个节点和下一个节点的引用,该怎么办? 现在我们可以在头部和尾部进行插入和删除,而无需任何遍历。

Diagram of a doubly linked list
https://commons.wikimedia.org/w/index.php?curid=2245165 https: //commons.wikimedia.org/w/index.php?curid = 2245165

Great, let’s implement it. We can start by modifying our ListNode slightly and List classes slightly:

太好了,让我们实现它。 我们可以从稍微修改ListNode和List类开始:

Image for post
ListNode and DoublyLinkedList class definitions
ListNode和DoublyLinkedList类定义

As you can see, we now have our data, and two pointers, previous and next, and a reference to the tail of our list.

如您所见,现在我们有了数据,还有两个指针(上一个和下一个),以及对列表尾部的引用。

Inserting and deleting nodes will be very similar to what we did when using singly linked lists, but now we do not need to keep track of the previous node (we just use our trusty pointer). Keep in mind that in every operation we need to update two pointers instead of one.

插入和删除节点与使用单链接列表时非常相似,但是现在我们不需要跟踪上一个节点(我们只使用可信赖的指针)。 请记住,在每个操作中,我们需要更新两个指针而不是一个。

With doubly linked lists, we can start traversing the list and add or remove elements from both the head and the tail. I’ve created this CodePen for you to play with a doubly linked list.

使用双向链接列表,我们可以开始遍历列表,并从头和尾添加或删除元素。 我已经创建了此CodePen,供您与双向链表一起使用。

So why do we need another data structure?

那么为什么我们需要另一个数据结构呢?

Data structures are tools that help developers get the job done. If you needed to drive a nail into the wall, a hammer would be the tool to get the job done. A sturdy screwdriver could also get the job done, but with a hammer at hand, why choose another tool?

数据结构是可帮助开发人员完成工作的工具。 如果您需要将钉子钉在墙上,锤子将是完成工作的工具。 坚固的螺丝刀也可以完成工作,但是手握锤子,为什么还要选择其他工具?

The same applies to data structures. Different data structures are better suited for different operations. If your application requires a lot of random access you should probably use an array. But if your application requires a lot of insertions and deletions at the head, a linked list is probably a better choice. Linked lists can be useful to implement some other data structures, such as stacks or queues. Oftentimes, edges in graphs are represented as adjacency lists, too. If you think of a chess game, you can think of the sequence of moves as a linked list. If you ever read a Wikipedia article and fall into a black hole and clicking link after link, you can think of this as a linked list as well: when you hit back on your browser, you are traversing the linked list of your browsers recent history.

数据结构也是如此。 不同的数据结构更适合于不同的操作。 如果您的应用程序需要大量随机访问,则可能应使用数组。 但是,如果您的应用程序需要大量插入和删除操作,则链表可能是一个更好的选择。 链接列表对于实现某些其他数据结构(例如堆栈或队列)很有用。 通常,图中的边也被表示为邻接表。 如果您想下象棋游戏,可以将移动顺序视为一个链表。 如果您曾经阅读过Wikipedia文章并陷入黑洞,然后单击链接之间的链接,那么您也可以将其视为链接列表:当您回退浏览器时,您正在遍历浏览器的最近历史的链接列表。

Feel free to try things out to get more comfortable with linked lists. Keep in mind these implementations touch just the fundamentals. Here are some other functions that you can try to implement to get a better understanding of linked lists:

随意尝试一下,以使链接列表更舒适。 请记住,这些实现仅涉及基础知识。 您可以尝试实现以下一些其他功能,以更好地了解链接列表:

  • Think about how we can access elements by “index”.

    考虑一下我们如何通过“索引”访问元素。
  • Using the previous search, how can we insert and delete an element at index i?

    使用前面的搜索,我们如何在索引i处插入和删除元素?

  • In our doubly linked list, implement a search/delete/insert at index i from the tail.

    在我们的双向链接列表中,从尾部开始在索引i处执行搜索/删除/插入。

  • Write a function to calculate the size of the list (without using our class variable)

    编写一个函数来计算列表的大小(不使用我们的类变量)
  • JavaScript’s function concat() is used to merge two arrays. Think of how you could merge two linked lists (hint: This is a very fast operation!)

    JavaScript的函数concat()用于合并两个数组。 考虑如何合并两个链表(提示:这是一个非常快的操作!)

Groner, Loiane. Learning JavaScript Data Structures and Algorithms: Write complex and powerful JavaScript code using the latest ECMAScript, 3rd Edition, Packt Publishing, Limited, 2018.

洛亚恩·格罗纳。 学习JavaScript数据结构和算法:使用最新的ECMAScript,3rd Edition (Packt Publishing,Limited,2018)编写复杂而强大JavaScript代码

Bae, Sammie. Javascript Data Structures and Algorithms: An Introduction to Understanding and Implementing Core Data Structure and Algorithm Fundamentals. Apress, 2019.

裴萨米Javascript数据结构和算法:理解和实现核心数据结构和算法基础知识简介。 Apress,2019年。

翻译自: https://medium.com/@camilogomezmusic/linked-lists-using-javascript-a-beginners-guide-e498709db928

javascript链表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值