建立单链表 单链表的插入
I imagine I speak for most developers when I say learning data structures is a little D-R-Y dry. Numerous suggestions online from seasoned developers or Udemy instructors would tell you to take it in small bites and with frequent breaks for the best chance of retaining the information.
我想当我说学习数据结构有点干时,我会为大多数开发人员讲话。 经验丰富的开发人员或Udemy讲师在网上提供的许多建议都会告诉您,一口咬一口并经常休息,以最大程度地保留信息。
I can personally say this strategy has helped me keep the information straight and even be able to recall it from memory when working on leetcode problems and the like.
我个人可以说这种策略帮助我保持了信息的完整性,甚至在处理leetcode问题之类的问题时甚至能够从内存中调用它。
This blog ( the first in a series ) will work on covering the basics of a few data structures as well as a few methods we can write for them to give them some functionality which is built-in for more common data structures ( like arrays and objects ).
该博客(系列文章的第一篇)将介绍一些数据结构的基础知识以及我们可以为它们编写的一些方法,以为它们提供一些内置于更常见的数据结构(例如数组和数组)的功能。对象)。
I am by no means an expert and reading this blog will not make you one, but maybe the way I explain something will help it stick or set you down a good path to mastering some of these things.
我绝不是专家,阅读此博客不会帮助您,但是也许我以某种方式进行解释会帮助它坚持或使您掌握一些这些东西。
那么什么是单链表 (So What’s a Singly Linked List)
A singly linked list is a collection of nodes each of which has some piece of data, and a ‘pointer’ directing you to the next node in the list.
单链列表是节点的集合,每个节点都有一些数据,还有一个“指针”将您定向到列表中的下一个节点。
Drawn out in a diagram it may look something like this.
在图中绘制出来可能看起来像这样。
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/19eb82dd0accdffec4471f12f4c068d3.png)
In the above example, each of the circles represents a node. Its value, or the data it is storing, is the number ( but could be a string, object, etc. ) The arrow is representing a pointer showing us to the next node.
在上面的示例中,每个圆圈代表一个节点。 它的值或存储的数据是数字 (但可以是字符串,对象等。)箭头表示一个指针,向我们显示了下一个节点。
A Singly Linked List has a few characteristics, or things we keep track of which will help us work with the data structure more easily and help us prove the methods we write are working in the way we expect.
单链表具有一些特征,或者我们跟踪的事物将帮助我们更轻松地处理数据结构,并帮助我们证明编写的方法以预期的方式运行。
头 (Head)
The head is simply the first item in our list. Remember, the nodes in a Linked List are not indexed like an array and pointers only point in one direction.
头部只是我们列表中的第一项。 请记住,链表中的节点没有像数组那样被索引,并且指针仅指向一个方向。
尾巴 (Tail)
The tail is, you guessed it, the final item in our list. The key take away about the tail is that it has no pointer. Since it is the last item in our list there is nothing for it to point to.
您猜对了,尾部是我们列表中的最后一项。 带走尾巴的关键是它没有指针。 由于这是我们列表中的最后一项,因此没有什么可指向的。
长度 (Length)
Length is simply a numerical representation of how many nodes our list contains. Arrays have the built-in .length
method to give us this information, for linked lists we are on our own to manage this.
长度只是我们的列表包含多少个节点的数字表示。 数组具有内置的.length
方法来为我们提供此信息,对于链接列表,我们可以自行管理。
给我看一些代码! (Show me some Code!)
Creating a class for both a Node ( list item ) and a Singly Linked List is pretty simple once you know its shape.
一旦知道Node的形状,就可以为Node(列表项)和单链接列表创建类非常简单。
By itself, these class definitions have potential but are really not very functional right now. Part of my love for arrays comes from the built-in methods I use to traverse, filter, add to, take from, and search those arrays and solve problems.
这些类定义本身具有潜力,但实际上目前还不是很实用。 我对数组的热爱部分来自于我用来遍历,过滤,添加,提取和搜索这些数组并解决问题的内置方法。
Since this linked list is our own creation we get the pleasure of writing those methods ourselves. ( we of course can add many more to suit our specific individual needs.
由于此链表是我们自己创建的,因此我们很高兴自己编写这些方法。 (我们当然可以添加更多以满足我们特定的个人需求。
让我们添加两种方法来入门 (Let’s Add Two Methods to Get us Started)
推() (push())
Push()
is going to allow us to start adding things to our list. More specifically it is going to function like Array.push()
and add our passed in value to the end of our list.
Push()
将允许我们开始将内容添加到列表中。 更具体地说,它将像Array.push()
一样起作用,并将传入的值添加到列表的末尾。
Pseudocode First.
伪代码优先。
define function called push()
定义称为push()的函数
it takes one argument, the value you would like added to the end of your list
它带有一个参数,您想要添加到列表末尾的值
create a new node using the passed in value
使用传入的值创建一个新节点
if the list is empty, the head and the tail should be set to our new node
如果列表为空,则应该将头和尾设置为新节点
otherwise, the current tail should point to our new node then the tail should be re-assigned to our new node
否则,当前尾部应指向我们的新节点,然后将尾部重新分配给我们的新节点
increment the length by one
将长度增加一
return the linked list
返回链表
I encourage you to try it out on your own and see what you come up with. I’ll share the final code below
我鼓励您自己尝试一下,看看您的想法。 我将在下面分享最终代码
![Image for post](https://i-blog.csdnimg.cn/blog_migrate/56834abd1bbefabae4b3ff401c86722a.png)
Did you try it? Here’s what I came up with.
你试过了吗? 这是我想出的。
Not too confusing this one. We start by making a new Node ( a list item ) using the value we passed to the function. We check for an empty list first; I did this by seeing if !this.head
but you could also check this.length === 0
also. If we have a list with at least one item we hit the else
block and proceed with setting our current tail’s next to our newly created node
after this assignment, we can set this.tail
to node
, increment the length, and return the list.
不要太困惑这个。 我们首先使用传递给函数的值创建一个新的Node(列表项)。 我们首先检查一个空列表; 我通过查看!this.head
做到这一点,但是您也可以检查this.length === 0
。 如果我们有一个包含至少一项的列表,我们点击else
块,并在分配后继续在新创建的node
旁边设置当前尾巴,我们可以将this.tail
设置为node
,增加长度,然后返回列表。
Let’s do another.
让我们再做一次。
pop() (pop())
A little more challenging in my opinion.
pop()
will remove the last item from the list.我认为更具挑战性。
pop()
将从列表中删除最后一项。Pseudocode first.
伪代码优先。
define a function called pop() it takes no arguments
定义一个不带参数的函数pop()
If the list is empty return undefined
如果列表为空,则返回undefined
find the second to last value in the list
在列表中找到倒数第二个值
assign it to be the tail of our list; set its next property to null
将其指定为我们列表的末尾; 将其下一个属性设置为null
decrement the length —
减少长度-
if after removing the item the list is empty make sure both the head and the tail are set to null.
如果在删除项目后列表为空,请确保将头和尾都设置为null。
return the node that was removed from the list.
返回从列表中删除的节点。
Take a crack at it and I will show you what I came up with below
破解一下,我将在下面向您展示我的想法
How’d you do?
你好吗
See my implementation below, and then I’ll step through it.
请在下面查看我的实现,然后逐步完成。
There were two big hurdles to write this method.
编写此方法有两个大障碍。
- to properly remove the last item you have to re-assign the tail to the second to last item. This preserves our Linked List structure 要正确删除最后一个项目,您必须将尾巴重新分配到倒数第二个项目。 这保留了我们的链表结构
our
nodes
do not have indices. In order to get the second to last item in the linked list you needed to go through each one until you found it ( since our pointers only point in one direction )我们的
nodes
没有索引。 为了获得链表中倒数第二个项目,您需要遍历每个项目,直到找到它为止(因为我们的指针仅指向一个方向)
To iterate through the list I used a while loop.
为了遍历列表,我使用了while循环。
I started with a current
variable to keep track of the list item I was iterating over and newTail
to keep track of the item before current. When we reach the end of the list this will be the second to last item.
我从一个current
变量开始,以跟踪正在迭代的列表项,而newTail
则在之前跟踪该项 当前。 当我们到达列表的末尾时,这将是倒数第二个项目。
The while loop is exited when we reach the end of the list because current
( which would be this.tail
does not have a next ( pointer )
当我们到达列表的末尾时,退出while循环,因为current
(本为this.tail
没有下一个(指针)
We set this.tail
to our newTail
and make sure to remove the connection to our old tail by setting our newly assigned this.tail
‘s .next
to null
我们将this.tail
设置为newTail
并通过将新分配的this.tail
的.next
为null
来确保删除与旧尾巴的连接
We then decrement this.length
and see if our list is now empty. If it is we make sure to set this.head
and this.tail
to null. ( take this conditional out and check the behavior to see why )
然后,我们递减this.length
并查看列表是否为空。 如果是,请确保将this.head
和this.tail
设置为null。 (删除此条件并检查行为以查看原因)
Once you’ve got these methods down try to implement some of your other favorite built-in methods ( shift(), unshift(), insert() )and even some others that might be useful to have available to you( reverse(), get(index) set(index) ) .
一旦您掌握了这些方法,请尝试实现一些其他您喜欢的内置方法(shift(),unshift(),insert()),甚至其他一些可能对您有用的内置方法(reverse() ,get(index)set(index))。
Data structures are sometimes hard. Heck, I would venture a guess and say most of the time they are hard. Work on them one small bite at a time, test them step through your code with the debugger or handwritten examples. Better yet find an algorithm visualizer to help you see it happen then work on pseudocode to explain what is happening. I even explained it to an eight-year-old using string connected to notecards with numbers on them to really force myself to explain it in the simplest of terms and break it down step by step.
数据结构有时很难。 哎呀,我大胆猜测一下,然后说,大多数时候他们都很努力。 一次一小段地处理它们,并通过调试器或手写示例对它们进行逐步测试。 最好还是找到一个算法可视化工具,以帮助您查看它的发生,然后使用伪代码来解释正在发生的事情。 我什至向一个八岁的孩子解释了这一点,使用了与笔记卡相连的字符串,上面带有数字,这确实迫使我自己用最简单的术语来解释它,并一步一步地分解它。
I’ve included a few resources I’ve used for studying as well as a gist with more methods I’ve written for singly-linked lists in case you would like to check them out.
我提供了一些我曾经学习过的资源,以及一些我为单链列表编写的更多方法的要点,以防万一您想将它们检出。
快乐黑客! (Happy Hacking!)
翻译自: https://medium.com/@robert.keller22/lets-talk-singly-linked-lists-29fe52a93410
建立单链表 单链表的插入