<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ 数据结构 - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ freeCodeCamp 是一个免费学习编程的开发者社区，涵盖 Python、HTML、CSS、React、Vue、BootStrap、JSON 教程等，还有活跃的技术论坛和丰富的社区活动，在你学习编程和找工作时为你提供建议和帮助。 ]]>
        </description>
        <link>https://www.freecodecamp.org/chinese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ 数据结构 - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/chinese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 08 Jul 2026 14:31:39 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/chinese/news/tag/data-structures/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ JavaScript 中的数据结构 ]]>
                </title>
                <description>
                    <![CDATA[ 原文：Data Structures in JavaScript – With Code Examples [https://www.freecodecamp.org/news/data-structures-in-javascript-with-examples/] ，作者：Germán Cocca [https://www.freecodecamp.org/news/author/gercocca/] 大家好，在这篇文章中，我们将看一看计算机科学和软件开发中的一个重要话题：数据结构。 数据结构是任何一个软件开发从业人员必须知道的内容，但当你刚开始学习的时候，可能觉得这个话题难以理解，甚至有些吓人。 在这篇文章中，我会简单介绍什么是数据结构，它们在什么时候有用，以及如何用 JavaScript 来实现这些数据结构。 让我们开始吧！ 目录  * 什么是数据结构  * 数组  * 对象（哈希表）  * 栈  * 队列  * 链表 * 单链表     * 双链表      ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/data-structures-in-javascript-with-examples/</link>
                <guid isPermaLink="false">6291607b60237306d260726d</guid>
                
                    <category>
                        <![CDATA[ 数据结构 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ PapayaHUANG ]]>
                </dc:creator>
                <pubDate>Fri, 27 May 2022 02:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2022/05/pexels-clem-onojeghuo-175771.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>原文：<a href="https://www.freecodecamp.org/news/data-structures-in-javascript-with-examples/">Data Structures in JavaScript – With Code Examples</a>，作者：<a href="https://www.freecodecamp.org/news/author/gercocca/">Germán Cocca</a></p><!--kg-card-begin: markdown--><p>大家好，在这篇文章中，我们将看一看计算机科学和软件开发中的一个重要话题：数据结构。</p>
<p>数据结构是任何一个软件开发从业人员必须知道的内容，但当你刚开始学习的时候，可能觉得这个话题难以理解，甚至有些吓人。</p>
<p>在这篇文章中，我会简单介绍什么是数据结构，它们在什么时候有用，以及如何用 JavaScript 来实现这些数据结构。</p>
<p>让我们开始吧！</p>
<h2 id="">目录</h2>
<ul>
<li><a href="#what-is-a-data-structure">什么是数据结构</a></li>
<li><a href="#arrays">数组</a></li>
<li><a href="#objects-hash-tables-">对象（哈希表）</a></li>
<li><a href="#stacks">栈</a></li>
<li><a href="#queues">队列</a></li>
<li><a href="#linked-lists">链表</a>
<ul>
<li><a href="#singly-linked-list">单链表</a></li>
<li><a href="#doubly-linked-lists">双链表</a></li>
</ul>
</li>
<li><a href="#trees">树</a>
<ul>
<li><a href="#binary-trees">二叉树</a></li>
<li><a href="#heaps">堆</a></li>
</ul>
</li>
<li><a href="#graphs">图</a>
<ul>
<li><a href="#undirected-and-directed-graphs">无向图和有向图</a></li>
<li><a href="#weighted-and-unweighted-graphs">加权图和非加权图</a></li>
<li><a href="#how-to-represent-graphs">如何表达图</a></li>
</ul>
</li>
<li><a href="#roundup">总结</a></li>
</ul>
<h1 id="what-is-a-data-structure">什么是数据结构</h1>
<p>在计算机科学中，数据结构是<strong>一种组织、管理和存储数据的形式</strong>，这种形式<strong>方便数据访问和修改</strong>。</p>
<p>准确来讲，数据结构是<strong>数据值的合集</strong>、数据间的<strong>关系</strong>，以及可以应用到数据的函数和<strong>操作</strong>。</p>
<p>这些概念乍一听有些抽象费解，但值得你去思考。如果你已经编写过一段时间代码，你肯定使用过数据结构。</p>
<p>你使用过数组或者对象吗？它们就是数据结构。它们都是相互关联值的合集，并且可供你操作。😉</p>
<pre><code class="language-javascript">// 值 1、2、3 的合集
const arr = [1, 2, 3]

// 每一个值都是彼此相关联的，因为每一个值都在数组中具备自己的索引序号
const indexOfTwo = arr.indexOf(2)
console.log(arr[indexOfTwo-1]) // 1
console.log(arr[indexOfTwo+1]) // 3

// 我们可以对数组进行很多操作，例如给数组添加一个新的值
arr.push(4)
console.log(arr) // [1,2,3,4]
</code></pre>
<p>JavaScript 包含<strong>原始（内置）</strong> 和 <strong>非原始（非内置）</strong> 两种数据结构。</p>
<p>原始数据结构是编程语言默认的、可以拿来就用（如数组和对象）的；而非原始数据结构不是默认的、如果需要使用的话，你必须先编写出来。</p>
<p>不同的数据结构对应不同的操作场景。你或许可以使用内置数据结构处理大部分编程任务，但当遇到特殊任务的时候，非原始数据机构可以派上用场。</p>
<p>让我们一起来看一看最流行的数据结构，它们是怎么运行的，在哪些场合适用，以及如何使用 JavaScript 编写这些数据结构。</p>
<h1 id="arrays">数组</h1>
<p><strong>数组</strong>是存储在连续内存位置的项目合集。</p>
<p>数组内的每一个元素都可以通过其<strong>索引</strong>（位置）访问。数组的索引通常从 0 开始，所以在一个包含 4 个元素的数组中，第三个元素的索引为 2。</p>
<pre><code class="language-javascript">const arr = ['a', 'b', 'c', 'd']
console.log(arr[2]) // c
</code></pre>
<p>数组的<strong>长度</strong>属性定义了数组包含的元素数量。如果一个数组包含 4 个元素，我们就可以说这个数组的长度为 4。</p>
<pre><code class="language-javascript">const arr = ['a', 'b', 'c', 'd']
console.log(arr.length) // 4
</code></pre>
<p>在一些编程语言中，一个数组中只能存储同一种数据类型的元素，在数组被创建的时候就必须定义数组的长度，并且不可以修改。</p>
<p>但 JavaScript 的数组并不是这样，在 JavaScript 中，同一数组可以存储<strong>任何数据类型</strong>的元素，数组<strong>长度</strong>是<strong>动态</strong>的（也就是说可以按需更改数组长度）。</p>
<pre><code class="language-javascript">const arr = ['store', 1, 'whatever', 2, 'you want', 3]
</code></pre>
<p>JavaScript 数组可以存储任何数据类型的值，也就意味着可以存储数组。一个包含其他数组的数组被称为<strong>多维数组</strong>。</p>
<pre><code class="language-javascript">const arr = [
    [1,2,3],
    [4,5,6],
    [7,8,9],
]
</code></pre>
<p>JavaScript 数组有许多内置的属性和方法，可以针对不同目的来使用，如从数组添加或者删除元素、给数组排序、过滤数组，以及我们知道的数组长度等，数组的完全属性和方法列表可以在<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">这里</a>找到。😉</p>
<p>在数组中每一个元素都对应一个索引，索引跟元素位于数组位置相关。如果我们在数组末尾添加一个新的元素，则这个元素的索引为之前数组最后一位索引加一。</p>
<p>但当我们想要在数组的<strong>开头或者中间</strong>添加或者删除元素的话，添加或删除的这个元素之后的所有元素的<strong>索引</strong>都会<strong>变化</strong>。这样会增加计算成本，也是这种数据结构的缺点之一。</p>
<p>当需要存储独立值以及在数据结构末尾添加和删除值的时候，数组十分有效。但当需要在结构中添加删除元素，其他数据结构会更有效。（我们会在后文提到）</p>
<h1 id="objects-hash-tables-">对象（哈希表）</h1>
<p>在 JavaScript 中，<strong>对象</strong>是<strong>键值对</strong>的集合。在其他编程语言中，这种数据结构也被称作<strong>映射</strong>、<strong>字典</strong>和<strong>哈希表</strong>。</p>
<p>一个典型的 JS 对象如下：</p>
<pre><code class="language-javascript">const obj = {
    prop1: "I'm",
    prop2: "an",
    prop3: "object"
}
</code></pre>
<p>我们使用花括号声明对象，在每一个键之后紧跟一个冒号和对应的值。</p>
<p>需要注意的是，在同一个对象中所有的键都是独一无二的，不可以出现两个命名相同的键。</p>
<p>对象可以存储值和函数。在对象的语境中，我们将值叫作属性，将函数叫作方法。</p>
<pre><code class="language-javascript">const obj = {
    prop1: "Hello!",
    prop3: function() {console.log("I'm a property dude!")
}}
</code></pre>
<p>访问属性有两种语法，<code>object.property</code>和<code>object["property"]</code>。访问方法可以调用<code>object.method()</code>。</p>
<pre><code class="language-javascript">console.log(obj.prop1) // "Hello!"
console.log(obj["prop1"]) // "Hello!"
obj.prop3() // "I'm a property dude!"
</code></pre>
<p>赋值的语法也类似：</p>
<pre><code class="language-javascript">obj.prop4 = 125
obj["prop5"] = "The new prop on the block"
obj.prop6 = () =&gt; console.log("yet another example")

console.log(obj.prop4) // 125
console.log(obj["prop5"]) // "The new prop on the block"
obj.prop6() // "yet another example"
</code></pre>
<p>和数组一样，JavaScript 对象也有内置的方法供我们进行不同的操作，或者获取特定对象的信息，完整内容可以查看<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">这里</a>。</p>
<p>对象是将有相同之处或者相互关联的数据放在一起的好办法。同时，因为对象的属性是独一无二的，当想要根据特定条件来区分数据的时候，对象可以派上用场。</p>
<p>可以使用对象来记录有多少人喜欢不同的食物：</p>
<pre><code class="language-javascript">const obj = {
    pizzaLovers: 1000,
    pastaLovers: 750,
    argentinianAsadoLovers: 12312312312313123
}
</code></pre>
<h1 id="stacks">栈</h1>
<p>栈是一种以列表的方式来存储信息的数据结构，添加和删除栈的元素遵循 <strong>LIFO 模式（后进先出）</strong>。在栈中，不允许按照元素顺序来添加或删除元素，只能遵循 LIFO 模式。</p>
<p>你可以想象桌面有一叠纸，来思考栈是如何运作的。你只能在这叠纸上方添加更多纸张，也只能在最上方取出纸张。这就是 LIFO，后进先出。 😉</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/istockphoto-178580846-170667a.jpg" alt="一叠纸" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>一叠纸</figcaption>
</figure>
<p>只要确认元素遵循 <strong>LIFO模式</strong>，那么栈结构就可以派上用场。下面是栈的使用场景：</p>
<ul>
<li>JavaScript 的调用栈</li>
<li>在各种编程语言中管理函数调用</li>
<li>许多程序提供的撤销/重做功能</li>
</ul>
<p>有不止一种实现栈的方法，但是最简单的或许是<strong>在数组中使用 push 和 pop 方法</strong>。如果你仅通过 pop 和 push 的方法来添加和删除元素，你就遵循了 LIFO 模式，用栈的方法操作了数组。</p>
<p>另一个方法是列表，实现如下：</p>
<pre><code class="language-javascript">// 为栈的每一个节点创建一个类
class Node {
    // 每一个节点包含两个属性，其值以及一个指向下一个节点的指针
    constructor(value){
        this.value = value
        this.next = null
    }
}

// 为栈创建一个类
class Stack {
    // 栈有三个属性，第一个节点，最后一个节点，以及栈的大小
    constructor(){
        this.first = null
        this.last = null
        this.size = 0
    }
    // push 方法接受一个值，并将其添加到栈的“顶端”
    push(val){
        var newNode = new Node(val)
        if(!this.first){
            this.first = newNode
            this.last = newNode
        } else {
            var temp = this.first
            this.first = newNode
            this.first.next = temp
        }
        return ++this.size
    }
    // pop 方法删除栈“顶端”的值，并返回这个值
    pop(){
        if(!this.first) return null
        var temp = this.first
        if(this.first === this.last){
            this.last = null
        }
        this.first = this.first.next
        this.size--
        return temp.value
    }
}

const stck = new Stack

stck.push("value1")
stck.push("value2")
stck.push("value3")

console.log(stck.first) /* 
        Node {
        value: 'value3',
        next: Node { value: 'value2', next: Node { value: 'value1', next: null } }
        }
    */
console.log(stck.last) // Node { value: 'value1', next: null }
console.log(stck.size) // 3

stck.push("value4")
console.log(stck.pop()) // value4
</code></pre>
<p>栈方法的大 O 表示法为：</p>
<ul>
<li>插入 - O(1)</li>
<li>删除 - O(1)</li>
<li>查找 - O(n)</li>
<li>访问 - O(n)</li>
</ul>
<h1 id="queues">队列</h1>
<p>队列和栈的运作方式类似，但是元素遵循另一个添加和删除的模式。队列值遵循 <strong>FIFO 先进先出模式</strong>。在队列中，元素不按照顺序添加或删除，仅遵循 FIFO 模式。</p>
<p>下面这张排队购买食物的图可以帮助你思考这个概念。这里的逻辑是如果你先加入到队伍中，你就会先被服务。如果你是队伍的第一个，你就第一个离开队伍。FIFO。😉</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/pexels-picography-4481.jpg" alt="一队列的顾客" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>一队列的顾客</figcaption>
</figure>
<p>队列的使用场景：</p>
<ul>
<li>后台任务</li>
<li>打印/任务处理</li>
</ul>
<p>和栈一样，有不止一种实现队列的方式。但是最简单的是在数组中使用 push 和 shift 方法。</p>
<p>如果我们仅使用 push 和 shift 方法来添加和删除元素，我们就在数组中遵循了 FIFO 模式，将数组按照队列来操作。</p>
<p>另一个实现办法是列表，如下：</p>
<pre><code class="language-javascript">// 为队列每一个节点的类
class Node {
    //每一个节点包含两个属性，其值以及一个指向下一个节点的指针
    constructor(value){
        this.value = value
        this.next = null
    }
}

// 为队列创建类
class Queue {
    // 队列包含三个属性：第一个节点、最后一个节点、队列的大小
    constructor(){
        this.first = null
        this.last = null
        this.size = 0
    }
    // enqueue 方法接受一个值并将其添加到队列的末端
    enqueue(val){
        var newNode = new Node(val)
        if(!this.first){
            this.first = newNode
            this.last = newNode
        } else {
            this.last.next = newNode
            this.last = newNode
        }
        return ++this.size
    }
    // dequeue 方法删除队列“最前端”的元素，并返回
    dequeue(){
        if(!this.first) return null

        var temp = this.first
        if(this.first === this.last) {
            this.last = null
        }
        this.first = this.first.next
        this.size--
        return temp.value
    }
}

const quickQueue = new Queue

quickQueue.enqueue("value1")
quickQueue.enqueue("value2")
quickQueue.enqueue("value3")

console.log(quickQueue.first) /* 
        Node {
            value: 'value1',
            next: Node { value: 'value2', next: Node { value: 'value3', next: null } }
        }
    */
console.log(quickQueue.last) // Node { value: 'value3, next: null }
console.log(quickQueue.size) // 3

quickQueue.enqueue("value4")
console.log(quickQueue.dequeue()) // value1
</code></pre>
<p>队列方法的大 O 表示法：</p>
<ul>
<li>插入 - O(1)</li>
<li>删除 - O(1)</li>
<li>查询 - O(n)</li>
<li>访问 - O(n)</li>
</ul>
<h1 id="linked-lists">链表</h1>
<p><strong>链表</strong>是一种以<strong>列表</strong>存储值的数据结构，在列表中每一个值都被当作为一个<strong>节点</strong>，每一个节点都通过<strong>指针</strong>与列表的下一个值关联（若该节点是列表最后一个元素则下一个值为 null）。</p>
<p>有两种链表：<strong>单链表</strong>和<strong>双链表</strong>。两种链表的运作方式类似，但是在单链表中每一个节点有<strong>单指针</strong>指向<strong>下一个节点</strong>，在双链表中，每一个节点有<strong>双指针</strong>，一个指向<strong>下一个节点</strong>，一个指向<strong>上一个节点</strong>。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/linked-list.png" alt="在单链表中每一个节点有单指针" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>在单链表中每一个节点有单指针</figcaption>
</figure>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/doubly-linked-list.png" alt="在双链表中每一个节点有双指针" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>在双链表中每一个节点有双指针</figcaption>
</figure>
<p>列表的第一个元素被当作<strong>头</strong>，列表的最后一个元素被当作<strong>尾</strong>。和数组一样，列表的<strong>长度</strong>由列表中的元素个数决定。</p>
<p>列表和数组主要不同包括：</p>
<ul>
<li><strong>列表没有索引</strong>，列表中的每一个值仅“知道”其通过指针连接到的值。</li>
<li>因为列表没有索引，所以我们<strong>不能随机访问列表中的元素</strong>。当我们想要访问一个值，必须通过从头到尾遍历整个列表的方法。</li>
<li>没有索引的好处是<strong>添加或删除</strong>列表中任意部分比在数组中更高效。我们只需要重新分配指针指向的“相邻”值，但是在数组中，我们需要重新分配余下所有值的索引。</li>
</ul>
<p>和其他所有数据结构一样，可以采用不同的<strong>方法</strong>来操作以链表存储的数据。通常会使用：push（在尾部添加）、pop（在尾部删除）、unshift（在头部添加）、shift（在头部删除）、get（获取）、set（设置）、remove（删除）和 reverse（反转）。</p>
<p>我们先来看看如何实现单链表，再来看看如何实现双链表。</p>
<h2 id="singly-linked-list">单链表</h2>
<p>完全实现单链表的代码如下：</p>
<pre><code class="language-javascript">// 为列表中的每一个节点创建一个类
class Node{
    // 每一个节点有两个属性：其值和指向下一个值的指针
    constructor(val){
        this.val = val
        this.next = null
    }
}

//为列表创建一个类
class SinglyLinkedList{
    // 列表有三个属性，头、尾和列表大小
    constructor(){
        this.head = null
        this.tail = null
        this.length = 0
    }
    // 向 push 方法传入一个值作为参数，并将其赋值给队列的尾
    push(val) {
        const newNode = new Node(val)
        if (!this.head){
            this.head = newNode
            this.tail = this.head
        } else {
            this.tail.next = newNode
            this.tail = newNode
        }
        this.length++
        return this
    }
    // pop 方法删除队列尾
    pop() {
        if (!this.head) return undefined
        const current = this.head
        const newTail = current
        while (current.next) {
            newTail = current
            current = current.next
        }
        this.tail = newTail
        this.tail.next = null
        this.length--
        if (this.length === 0) {
            this.head = null
            this.tail = null
        }
        return current
    }
    // shift 方法删除队列头
    shift() {
        if (!this.head) return undefined
        var currentHead = this.head
        this.head = currentHead.next
        this.length--
        if (this.length === 0) {
            this.tail = null
        }
        return currentHead
    }
    // unshift 方法将一个值作为参数并赋值给队列的头
    unshift(val) {
        const newNode = new Node(val)
        if (!this.head) {
            this.head = newNode
            this.tail = this.head
        }
        newNode.next = this.head
        this.head = newNode
        this.length++
        return this
    }
    // get 方法将一个索引作为参数，并返回此索引所在节点的值
    get(index) {
        if(index &lt; 0 || index &gt;= this.length) return null
        const counter = 0
        const current = this.head
        while(counter !== index) {
            current = current.next
            counter++
        }
        return current
    }
    // set 方法将索引和值作为参数，修改队列中索引所在的节点值为传入的参数值
    set(index, val) {
        const foundNode = this.get(index)
        if (foundNode) {
            foundNode.val = val
            return true
        }
        return false
    }
    // insert 方法将索引和值作为参数，在队列索引位置插入传入的值
    insert(index, val) {
        if (index &lt; 0 || index &gt; this.length) return false
        if (index === this.length) return !!this.push(val)
        if (index === 0) return !!this.unshift(val)

        const newNode = new Node(val)
        const prev = this.get(index - 1)
        const temp = prev.next
        prev.next = newNode
        newNode.next = temp
        this.length++
        return true
    }
    // remove 方法将索引作为参数，在队列中删除索引所在的值
    remove(index) {
        if(index &lt; 0 || index &gt;= this.length) return undefined
        if(index === 0) return this.shift()
        if(index === this.length - 1) return this.pop()
        const previousNode = this.get(index - 1)
        const removed = previousNode.next
        previousNode.next = removed.next
        this.length--
        return removed
    }
    // reverse 方法反转队列和所有指针，让队列的头尾对调
    reverse(){
      const node = this.head
      this.head = this.tail
      this.tail = node
      let next
      const prev = null
      for(let i = 0; i &lt; this.length; i++) {
        next = node.next
        node.next = prev
        prev = node
        node = next
      }
      return this
    }
}
</code></pre>
<p>单链表的复杂度为：</p>
<ul>
<li>插入 - O(1)</li>
<li>删除 - O(n)</li>
<li>查找 - O(n)</li>
<li>访问 - O(n)</li>
</ul>
<h2 id="doubly-linked-lists">双链表</h2>
<p>如上文所述，双链表和单链表的区别在于双链表的前后两个节点之间由双指针相互连接，而单链表只有一个指向下一个值的指针。</p>
<p>双指针使得在特定场景下双链表比单链表的表现更好，但是也增加了存储空间的成本（存储双指针比单指针更占位置）。</p>
<p>完全实现双链表的代码类似于：</p>
<pre><code class="language-javascript">// 创建列表节点的类
class Node{
    // 每一个节点包含三个属性，其值，一个指向上一个节点的指针，一个指向下一个节点的指针
    constructor(val){
        this.val = val;
        this.next = null;
        this.prev = null;
    }
}

// 创建一个列表的类
class DoublyLinkedList {
    // 列表有三个属性，头，尾和列表的大小
    constructor(){
        this.head = null
        this.tail = null
        this.length = 0
    }
    // push 方法将值作为参数并赋值给队列尾
    push(val){
        const newNode = new Node(val)
        if(this.length === 0){
            this.head = newNode
            this.tail = newNode
        } else {
            this.tail.next = newNode
            newNode.prev = this.tail
            this.tail = newNode
        }
        this.length++
        return this
    }
    // pop 方法删除队列尾
    pop(){
        if(!this.head) return undefined
        const poppedNode = this.tail
        if(this.length === 1){
            this.head = null
            this.tail = null
        } else {
            this.tail = poppedNode.prev
            this.tail.next = null
            poppedNode.prev = null
        }
        this.length--
        return poppedNode
    }
    // shift 方法删除队列头
    shift(){
        if(this.length === 0) return undefined
        const oldHead = this.head
        if(this.length === 1){
            this.head = null
            this.tail = null
        } else{
            this.head = oldHead.next
            this.head.prev = null
            oldHead.next = null
        }
        this.length--
        return oldHead
    }
    // unshift 方法将值作为参数并赋值给队列头
    unshift(val){
        const newNode = new Node(val)
        if(this.length === 0) {
            this.head = newNode
            this.tail = newNode
        } else {
            this.head.prev = newNode
            newNode.next = this.head
            this.head = newNode
        }
        this.length++
        return this
    }
    // get 方法将索引作为参数并返回队列对应索引的值
    get(index){
        if(index &lt; 0 || index &gt;= this.length) return null
        let count, current
        if(index &lt;= this.length/2){
            count = 0
            current = this.head
            while(count !== index){
                current = current.next
                count++
            }
        } else {
            count = this.length - 1
            current = this.tail
            while(count !== index){
                current = current.prev
                count--
            }
        }
        return current
    }
    // set 方法将索引和值作为参数，修改队列中索引所在的节点值为传入的参数值
    set(index, val){
        var foundNode = this.get(index)
        if(foundNode != null){
            foundNode.val = val
            return true
        }
        return false
    }
    // insert 方法将索引和值作为参数，将值插入队列响应索引位置
    insert(index, val){
        if(index &lt; 0 || index &gt; this.length) return false
        if(index === 0) return !!this.unshift(val)
        if(index === this.length) return !!this.push(val)

        var newNode = new Node(val)
        var beforeNode = this.get(index-1)
        var afterNode = beforeNode.next

        beforeNode.next = newNode, newNode.prev = beforeNode
        newNode.next = afterNode, afterNode.prev = newNode
        this.length++
        return true
    }
}
</code></pre>
<p>双链表的大 O 表示法为：</p>
<ul>
<li>插入 - O(1)</li>
<li>删除 - O(1)</li>
<li>搜索 - O(n)</li>
<li>访问 - O(n)</li>
</ul>
<h1 id="trees">树</h1>
<p>树是一种以<strong>父子关系</strong>相连的节点之间的数据结构，也就是说节点之间相互依赖。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/images.png" alt="树结构" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>树结构</figcaption>
</figure>
<p>树由<strong>根</strong>节点（树的第一个节点）开始，其他所有由根发展出来的节点被称作<strong>子节点</strong>。树结构最底部的节点没有“后代”，被称为<strong>叶节点</strong>。树的<strong>高度</strong>由父子节点相连的层数决定。</p>
<p>和链表及数组不同的地方是，树是<strong>非线性</strong>的，程序可以在数据结构内选择不同的方向遍历数据，从而得出不同的值。</p>
<p>而在链表或者数组中，程序由一个端点开始遍历到另一端点，每一次都重复同样的路径。</p>
<p>构成树结构一个重要的要素是<strong>仅从父到子连接的节点是合法的</strong>。“亲属”之间或者由子向父节点是我连接都不被允许（这样的连接会形成图表，是另一种数据结构），另一个重要的要素是树只能有<strong>一个根节点</strong>。</p>
<p>程序中使用树的场景有：</p>
<ul>
<li>DOM 模型</li>
<li>人工智能中的情景分析</li>
<li>操作系统中的文件夹</li>
</ul>
<p>有不同<strong>类型</strong>的树，每一种类型的树的值都遵从不同的模式而组织起来，这样也就适用于不同的解决问题的场景。最常见的两种树是二叉树和堆。</p>
<h2 id="binary-trees">二叉树</h2>
<p>二叉树是每个节点最多只有两个节点的树结构。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/binary-tree.png" alt="二叉树" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>二叉树</figcaption>
</figure>
<p>二叉树的一个重要使用场景是搜索。用于搜索的二叉树被称为<strong>二叉查找树（BST）</strong>。</p>
<p>BST 和普通二叉树类似，只是内部的数据结构被排列成易于搜索的结构。</p>
<p>在 BST 中的值是排过序的，所有节点的左子节点的值要小于父节点，所有节点的右子节点的值要大于父节点。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/download--1-.png" alt="二叉查找树" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>二叉查找树</figcaption>
</figure>
<p>这样给值排过序的数据结构非常适合做搜索，因为树的每一层都可以对比是比父节点大还是小，在对比的过程中，我们可以逐步舍弃掉一半的数据得到最终我们需要的值。</p>
<p>当<strong>插入或者删除值</strong>的时候，我们的算法会进行如下步骤：</p>
<ul>
<li>检查是否存在根节点</li>
<li>如果存在根节点，检查这个需要添加或删除的值是比根节点大还是小</li>
<li>如果比根节点小，则检查左边是否有节点，并重复上面的步骤；如果左边没有节点，则将这个节点在当下位置添加或者删除</li>
<li>如果比根节点大，则检查右边有没有节点，并重复上述步骤；如果有变没有节点，则将这个节点在当下位置添加或者删除</li>
</ul>
<p>在 BST 中查找与上述方法类似，但是没有添加或者删除值，取而代之的是与节点比较我们搜寻的值的大小。</p>
<p>树的<strong>大 o</strong> 复杂度呈<strong>对数（log（n））</strong>。但是需要注意的是，想要实现这样的时间复杂度，必须保证树结构的每一步都是左右对称的，这样我们才可以在搜索的过程中“丢弃”一半的数据。如果在任意一边存储的值更多，树结构的搜索效率就会打折扣。</p>
<p>实现 BST 的方法如下：</p>
<pre><code class="language-javascript">// 我们创建树的节点
class Node{
    // 每一个节点有三个属性：其值，以及指向左节点的指针和指向右节点的指针
    constructor(value){
        this.value = value
        this.left = null
        this.right = null
    }
}
// 创建BST的类
class BinarySearchTree {
    // 这个树只有一个属性即根节点
    constructor(){
        this.root = null
    }
    // insert 方法将一个值作为参数，并将值插入树对应的位置
    insert(value){
        const newNode = new Node(value)
        if(this.root === null){
            this.root = newNode
            return this
        }
        let current = this.root
        while(true){
            if(value === current.value) return undefined
            if(value &lt; current.value){
                if(current.left === null){
                    current.left = newNode
                    return this
                }
                current = current.left
            } else {
                if(current.right === null){
                    current.right = newNode
                    return this
                } 
                current = current.right
            }
        }
    }
    // find 方法将值作为参数，遍历树寻找对应的值
    // 如果找到了，返回找到的值，如果没有找到，返回undefined
    find(value){
        if(this.root === null) return false
        let current = this.root,
            found = false
        while(current &amp;&amp; !found){
            if(value &lt; current.value){
                current = current.left
            } else if(value &gt; current.value){
                current = current.right
            } else {
                found = true
            }
        }
        if(!found) return undefined
        return current
    }
    // contain 方法将值作为参数，如果找到树中对应的值返回 true，如果没有找到则返回 false
    contains(value){
        if(this.root === null) return false
        let current = this.root,
            found = false
        while(current &amp;&amp; !found){
            if(value &lt; current.value){
                current = current.left
            } else if(value &gt; current.value){
                current = current.right
            } else {
                return true
            }
        }
        return false
    }
}
</code></pre>
<h2 id="heaps">堆</h2>
<p>堆是有特殊规则的树结构。主要有两种形式的堆：<strong>最大堆和最小堆</strong>。在最大堆中，父节点的值必须比子节点大；在最小堆中，父节点的值必须比子节点小。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/max_heap_example.jpg" alt="最大堆" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>最大堆</figcaption>
</figure>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/min_heap_example.jpg" alt="最小堆" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>最小堆</figcaption>
</figure>
<p>堆结构的规则不适用于<strong>相邻的两个节点</strong>，也就是说在同一层的节点除了必须比自己的父节点大或者小，不需要遵循其他规则。</p>
<p>另外，堆越紧凑越好，也就是每一层都尽可能填满空位，新的节点首先添加到左边。</p>
<p>堆，特别是<strong>二进制堆</strong>，通常被用来解决<strong>优先队列</strong>问题，也被运用到知名的算法问题——<a href="https://zh.wikipedia.org/wiki/%E6%88%B4%E5%85%8B%E6%96%AF%E7%89%B9%E6%8B%89%E7%AE%97%E6%B3%95">戴克斯特拉算法</a>。</p>
<p>优先队列是一种数据结构，在这种结构中，每一个元素都被关联了优先级，优先级高的元素优先展示出来。</p>
<h1 id="graphs">图</h1>
<p>图是一种有一组节点相互连接的数据结构。和树不一样的是，图并没有根或者叶节点，也没有“头”或者“尾”。不同的节点随机关联在一起，之间并没有父子关系。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/images-1.png" alt="图" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>图</figcaption>
</figure>
<p>图经常被应用于：</p>
<ul>
<li>社交网络</li>
<li>地理定位</li>
<li>推荐系统</li>
</ul>
<p>根据节点之间关联的特征，可以把图分成不同的类别：</p>
<h2 id="undirected-and-directed-graphs">有向图和无向图</h2>
<p>如果节点之间没有的关联没有定义方向，我们就称这个图为无向图。</p>
<p>在下图中我们可以看到节点 2 和节点 3 之间的关联没有方向性，我们可以从节点 2 到节点 3，也可以从节点 3 到节点 2。无定向意味着节点间的连接是双向的。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/Undirected_graph.svg.png" alt="无向图" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>无向图</figcaption>
</figure>
<p>你可能已经猜出来了，有向图就是完全相反的。让我们再次使用上面的图，这时节点之间的连接是有固定方向的。</p>
<p>在这幅图中，你可以由节点 A 到节点 B，但是不能从节点 B 到节点 A。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/images-1.png" alt="有向图" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>有向图</figcaption>
</figure>
<h2 id="weighted-and-unweighted-graphs">加权图和非加权图</h2>
<p>如果节点之间的连接被分配了权重，我们就称其为加权图。权重仅分配给了节点之间的连接，仅和连接相关，不和节点相关。</p>
<p>在下面的例子中我们可以看到，节点 0 和节点 4 之间连接的权重是 7；而节点 3 和节点 1 之间的权重是 4。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/1_P68VQPcnFXBo9XlA4pDNrg.png" alt="加权图" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>加权图</figcaption>
</figure>
<p>想要了解加权图，可以想象你需要向用户展现一个标注了不同地点的地图，你需要告诉用户从一个地方到另一个地方需要花多长时间。</p>
<p>加权图就可以用来表现这个场景，你可以使用节点来存储地点的信息，节点之间的连接就是两个地点之间的道路，连接的权重代表从一个地点到另一个地点的物理距离。</p>
<figure class="kg-card kg-card-image kg-card-hascaption">
    <img src="https://www.freecodecamp.org/news/content/images/2022/05/houbo.jpg" alt="加权图被大量应用在定位系统" class="kg-image" width="600" height="400" loading="lazy">
    <figcaption>加权图被大量应用在定位系统</figcaption>
</figure>
<p>你应该已经猜到了，无加权图即节点之间的连接没有被分配权重，所以节点间的连接没有额外的信息，只表达节点间的关系。</p>
<h2 id="how-to-represent-graphs">如何表达图</h2>
<p>在编码图的时候，主要可以使用两种方法：<strong>邻接矩阵</strong>和<strong>邻接列表</strong>。让我们分别看看这两种方法的优缺点。</p>
<p><strong>邻接矩阵是一个二维结构</strong>代表图的节点和节点之间的连接。</p>
<p>如果我们使用这个的例子：</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Untitled-Diagram.drawio.png" alt="Untitled-Diagram.drawio" width="600" height="400" loading="lazy"></p>
<p>我们的邻接矩阵会是这个样子：</p>
<table xmlns="http://www.w3.org/1999/xhtml" cellspacing="0" cellpadding="0" dir="ltr" border="1" style="table-layout:fixed;font-size:10pt;font-family:Arial;width:0px;border-collapse:collapse;border:none"><colgroup><col width="52"><col width="52"><col width="52"><col width="52"><col width="52"></colgroup><tbody><tr style="height:21px;"><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;-&quot;}">-</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;A&quot;}">A</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;B&quot;}">B</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;C&quot;}">C</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;D&quot;}">D</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;A&quot;}">A</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;B&quot;}">B</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;C&quot;}">C</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;D&quot;}">D</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td></tr></tbody></table>
<p>矩阵可以用表格来表示，列和行来代表图里的节点，单元格内的值表示节点之间连接，如果单元格的值为 1，则表示该位置的行和列是相关联的，如果是 0，则表示没有联系。</p>
<p>这个表格可以用简单的二维数组来表示：</p>
<pre><code class="language-javascript">[
    [0, 1, 1, 0]
    [1, 0, 0, 1]
    [1, 0, 0, 1]
    [0, 1, 1, 0]
]
</code></pre>
<p><strong>邻接列表</strong>可以使用<strong>键值对结构</strong>来表示，<strong>键代表节点</strong>而<strong>值代表对应节点的连接</strong>。</p>
<p>上面的例子，用邻接列表可以表达为：</p>
<pre><code class="language-javascript">{
    A: ["B", "C"],
    B: ["A", "D"],
    C: ["A", "D"],
    D: ["B", "C"],
}
</code></pre>
<p>每一个节点为一个键，对应的值是与节点相连接的节点组成的数组。</p>
<p>这就是邻接矩阵和列表的所有区别吗？除此之外，当我们需要添加或者删除节点的时候，列表会更加方便；而当我们需要查询某个节点之间的关联的话，矩阵更方便。</p>
<p>假设要在我们的图里添加一个新的节点：</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/Untitled-Diagram.drawio-1.png" alt="Untitled-Diagram.drawio-1" width="600" height="400" loading="lazy"></p>
<p>如果要用矩阵来表达的话，我们需要添加一个全新的列和行：</p>
<table xmlns="http://www.w3.org/1999/xhtml" cellspacing="0" cellpadding="0" dir="ltr" border="1" style="table-layout:fixed;font-size:10pt;font-family:Arial;width:0px;border-collapse:collapse;border:none"><colgroup><col width="52"><col width="52"><col width="52"><col width="52"><col width="52"><col width="52"></colgroup><tbody><tr style="height:21px;"><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;-&quot;}">-</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;A&quot;}">A</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;B&quot;}">B</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;C&quot;}">C</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;D&quot;}">D</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;E&quot;}">E</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;A&quot;}">A</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;B&quot;}">B</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;C&quot;}">C</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;D&quot;}">D</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;E&quot;}">E</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td></tr></tbody></table>
<p>但是在列表中，我们只需要在 B 的连接数组中添加一个值，以及再添加一个代表 E 的键值对就够了：</p>
<pre><code class="language-javascript">{
    A: ["B", "C"],
    B: ["A", "D", "E"],
    C: ["A", "D"],
    D: ["B", "C"],
    E: ["B"],
}
</code></pre>
<p>现在假设我们需要验证 B 和 E 之间是否存在连接，在矩阵中检查就非常简单，因为我们知道节点间关联的位置位于哪个单元格。</p>
<table xmlns="http://www.w3.org/1999/xhtml" cellspacing="0" cellpadding="0" dir="ltr" border="1" style="table-layout:fixed;font-size:10pt;font-family:Arial;width:0px;border-collapse:collapse;border:none"><colgroup><col width="52"><col width="52"><col width="52"><col width="52"><col width="52"><col width="52"></colgroup><tbody><tr style="height:21px;"><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;-&quot;}">-</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;A&quot;}">A</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;B&quot;}">B</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;C&quot;}">C</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;D&quot;}">D</td><td style="border-top:1px solid #000000;border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;E&quot;}">E</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;A&quot;}">A</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;B&quot;}">B</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#ffff00;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;C&quot;}">C</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;D&quot;}">D</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td></tr><tr style="height:21px;"><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;border-left:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;background-color:#efefef;font-weight:bold;" data-sheets-value="{&quot;1&quot;:2,&quot;2&quot;:&quot;E&quot;}">E</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:1}">1</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td><td style="border-right:1px solid #000000;border-bottom:1px solid #000000;overflow:hidden;padding:2px 3px 2px 3px;vertical-align:bottom;text-align:right;" data-sheets-value="{&quot;1&quot;:3,&quot;3&quot;:0}">0</td></tr></tbody></table>
<p>但如果是在列表中，我们不能马上得出结论，必须先遍历所有和 B 的连接相关的数组，来查看是否有 E。通过这个例子你就了解了两种形式的优劣了。</p>
<p>邻接列表的完全实现如下，我们把图限定在无向和无权重，来简化代码：</p>
<pre><code class="language-javascript">// 为图创建一个类
class Graph{
    // 图仅有一个属性，即邻接列表
    constructor() {
        this.adjacencyList = {}
    }
    // addNode 将节点值作为参数，如果邻接列表没有键的话，就把节点值传入邻接链表作为键
    addNode(node) {
        if (!this.adjacencyList[node]) this.adjacencyList[node] = []
    }
    // addConnection 将两个节点作为参数，并添加到每一个节点键对应的值的数组中
    addConnection(node1,node2) {
        this.adjacencyList[node1].push(node2)
        this.adjacencyList[node2].push(node1)
    }
    // removeConnection 方法将两个节点作为参数，并删除掉非自己节点对应数组里的值
    removeConnection(node1,node2) {
        this.adjacencyList[node1] = this.adjacencyList[node1].filter(v =&gt; v !== node2)
        this.adjacencyList[node2] = this.adjacencyList[node2].filter(v =&gt; v !== node1)
    }
    // removeNode 方法将节点作为参数，删除该节点所有的连接，并且删除列表中该节点相关的键
    removeNode(node){
        while(this.adjacencyList[node].length) {
            const adjacentNode = this.adjacencyList[node].pop()
            this.removeConnection(node, adjacentNode)
        }
        delete this.adjacencyList[node]
    }
}

const Argentina = new Graph()
Argentina.addNode("Buenos Aires")
Argentina.addNode("Santa fe")
Argentina.addNode("Córdoba")
Argentina.addNode("Mendoza")
Argentina.addConnection("Buenos Aires", "Córdoba")
Argentina.addConnection("Buenos Aires", "Mendoza")
Argentina.addConnection("Santa fe", "Córdoba")

console.log(Argentina)
// Graph {
//     adjacencyList: {
//         'Buenos Aires': [ 'Córdoba', 'Mendoza' ],
//         'Santa fe': [ 'Córdoba' ],
//         'Córdoba': [ 'Buenos Aires', 'Santa fe' ],
//         Mendoza: [ 'Buenos Aires' ]
//     }
// }
</code></pre>
<h1 id="roundup">总结</h1>
<p>以上就是全部内容。在这篇文章中我们介绍了计算机科学和软件开发中的主要数据结构。这些数据结构是许多程序的基础，所以学习这些知识非常有用。</p>
<p>虽然刚开始接触这个话题的时候，你会觉得非常抽象甚至有些害怕，但是我相信当你把这些数据结构当作解决日常任务的一种方式的时候，你会更理解它们。</p>
<p>希望你享受阅读这篇文章，并且从中受益。你可以在 <a href="https://www.linkedin.com/in/germancocca/">LinkedIn</a> 或者 <a href="https://twitter.com/CoccaGerman">Twitter</a> 上关注我。</p>
<p>我们下篇文章见！</p>
<p><img src="https://www.freecodecamp.org/news/content/images/2022/05/3cd.gif" alt="3cd" width="600" height="400" loading="lazy"></p>
<!--kg-card-end: markdown--> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 数据结构 101：数组——面向初学者的可视化指南 ]]>
                </title>
                <description>
                    <![CDATA[ 通过这篇文章了解你每天使用的数据结构 👋 你好，让我们从一些重要的背景开始。让我问你几个问题： ✅ 你在智能手机上听音乐吗？ ✅ 你在手机上保存联系人列表吗？ ✅ 你在比赛中见过排行榜吗？ 如果你对这些问题中的任何一个的回答是肯定的，那么几乎可以肯定你已经使用过数组，而你甚至不知道它！😃 数组是非常强大的数据结构，用于存储元素列表 。它们有无穷无尽的应用，在计算机科学领域非常重要。 在本文中，你将了解数组的优缺点、结构、操作和用例。 我们开始吧！ 👍 🔎 深入了解基本的数组结构 要了解它们的工作原理，将计算机的内存可视化为网格非常有帮助，如下所示。每条信息都存储在构成网格的其中一个小元素（正方形）中。 数组利用这种“网格”结构在相邻的内存位置存储相关信息的列表，以保证极高效率地找到这些值。🔳🔳🔳🔳 你可以将数组视为： 它们的元素在内存中彼此相邻。如果你需要访问其中多个数组，该过程会得到极大的优化，因为你的计算机已经知道该值的位置。 很棒，对吧？ 让我们来了解一下这在幕后是如何运行的！😃 📚 归类 数组被归类为同构数据结构，因为它们存储相同类型的元素 ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/data-structures-101-arrays-a-visual-introduction-for-beginners/</link>
                <guid isPermaLink="false">60bc9e2e176e4005380a79eb</guid>
                
                    <category>
                        <![CDATA[ 数据结构 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 编程 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chengjun.L ]]>
                </dc:creator>
                <pubDate>Sun, 06 Jun 2021 10:00:00 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2021/06/1_plaTqL5DDa2MgqeK-0EClg.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <h3 id="-">通过这篇文章了解你每天使用的数据结构</h3><p>👋 你好，让我们从一些重要的背景开始。让我问你几个问题：<br>✅ 你在智能手机上听音乐吗？<br>✅ 你在手机上保存联系人列表吗？<br>✅ 你在比赛中见过排行榜吗？</p><p><strong>如果你对这些问题中的任何一个的回答是肯定的，那么几乎可以肯定你已经使用过数组，而你甚至不知道它！</strong>😃 数组是非常强大的数据结构，用于存储<strong>元素列表</strong>。它们有无穷无尽的应用，在计算机科学领域非常重要。</p><p>在本文中，你将了解数组的优缺点、结构、操作和用例。</p><p>我们开始吧！ 👍</p><h3 id="--1"><strong><strong>🔎 深入了解基本的数组结构</strong></strong></h3><p>要了解它们的工作原理，将计算机的内存可视化为网格非常有帮助，如下所示。每条信息都存储在构成网格的其中一个小元素（正方形）中。</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/uxNDqnrhHuS197WjrTeak8WQq2QZKAJD5xp4" class="kg-image" alt="uxNDqnrhHuS197WjrTeak8WQq2QZKAJD5xp4" width="800" height="495" loading="lazy"></figure><p><strong>数组</strong>利用这种“网格”结构<strong>在相邻的内存位置存储相关信息的列表</strong>，以保证极高效率地找到这些值。🔳🔳🔳🔳</p><p><strong><strong>你可以将数组视为</strong>：</strong></p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/HjKZtf6JKxcrH8t51iRrId-4lTqjOlGtICip" class="kg-image" alt="HjKZtf6JKxcrH8t51iRrId-4lTqjOlGtICip" width="800" height="365" loading="lazy"></figure><p><strong>它们的元素在内存中彼此相邻。</strong>如果你需要访问其中多个数组，该过程会得到极大的优化，因为你的计算机已经知道该值的位置。</p><p>很棒，对吧？ 让我们来了解一下这在幕后是如何运行的！😃</p><h4 id="--2"><strong><strong>📚 归类</strong></strong></h4><p>数组被归类为<strong>同构数据结构</strong>，因为它们存储<strong>相同类型的元素</strong>。</p><p>它们可以存储数字、字符串、布尔值（真和假）、字符、对象等。但是<strong>一旦定义了数组将存储的值的类型，它的所有元素都必须是相同的类型。你不能“混合”不同类型的数据。</strong></p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/sbk9-CGxQ5VKddqpz9S12GxpR26I8f8e0hj6" class="kg-image" alt="sbk9-CGxQ5VKddqpz9S12GxpR26I8f8e0hj6" width="800" height="290" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/oS1i6uyY71HPvrPCVEqEVDpscFgyeUCAwlPN" class="kg-image" alt="oS1i6uyY71HPvrPCVEqEVDpscFgyeUCAwlPN" width="800" height="342" loading="lazy"></figure><h3 id="--3"><strong><strong>👀 读取值——魔法开始啦</strong>！</strong></h3><p>数组的惊人力量来自于它们<strong>访问值的效率</strong>。这是由于其网格状结构而实现的。让我们更详细地了解一下。🔍</p><p><strong><strong>当你创建一个数组</strong>，你：</strong><br>- 将它赋值给一个变量 👈<br>- 定义它存储元素的类型 🎈<br>- 定义它的大小（最多有多少个元素）📚</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/xzGLFN8ymKFdxyZWHk4YInJ6cyQQHxUJiJQX" class="kg-image" alt="xzGLFN8ymKFdxyZWHk4YInJ6cyQQHxUJiJQX" width="713" height="144" loading="lazy"></figure><p><strong><strong><strong><strong>💡</strong></strong> 注意</strong>：</strong>你分配给该变量的名称非常重要，因为稍后你将在代码中使用它来访问值和修改数组。</p><p>但是你怎么能告诉计算机你想访问哪个特定的值呢？这就是索引发挥重要作用的地方！</p><h4 id="1-"><strong><strong>1️⃣ 索引</strong></strong></h4><p>你<strong>通过索引</strong>来读取数组中的某个值。这是一个数字，指的是存储值的位置。</p><p>正如你在下图中所看到的，数组中的第一个元素的索引是 0。当你向右移动时，内存中每个空间的索引都会增加 1。</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/TuWNHRYkAgpBEjuszG9DElXUIAf8Osw2z--7" class="kg-image" alt="TuWNHRYkAgpBEjuszG9DElXUIAf8Osw2z--7" width="796" height="324" loading="lazy"></figure><p><strong><strong><strong><strong>💡</strong></strong> </strong>注意：</strong>我知道从 0 而不是 1 开始计数，起初看起来很奇怪，但这被称为<a href="https://en.wikipedia.org/wiki/Zero-based_numbering">基于零的编号</a>。这在计算机科学中很常见。</p><p><strong><strong><strong><strong>读取一个元素的通用语法是</strong></strong></strong>：<strong><strong><strong><code>&lt;ArrayVariable&gt;[&lt;index&gt;]</code></strong></strong></strong></strong></p><p><strong><strong><strong><strong>例如</strong></strong></strong>：</strong><br>如果你的数组存储在变量 <code><strong><strong><strong><strong>myArray</strong></strong></strong></strong></code> 中，并且你想访问第一个元素（在索引 0 处），那么你将使用 <code><strong><strong><strong><strong>myArray[0]</strong></strong></strong></strong></code><strong>。</strong></p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/Yu9nSlzmHkZV4e7f7sulFIamSwWONw4wNcpg" class="kg-image" alt="Yu9nSlzmHkZV4e7f7sulFIamSwWONw4wNcpg" width="800" height="360" loading="lazy"></figure><h4 id="2-"><strong><strong>2️⃣ 内存</strong></strong></h4><p>现在你知道如何读取值了，让我们看看数组是如何存储在计算机内存中的。当你定义数组的大小时，从那一刻起，内存中的所有空间都将被“保留”以供将来可能要插入的值使用。</p><p><strong><strong><strong><strong>💡 注意</strong></strong></strong>：</strong>如果你没有用值填充数组，则该空间将被保留并为空，直到你填充数组为止。</p><p><strong><strong>例如</strong>：</strong><br>假设你定义了一个大小为 5 的数组，但只插入了一个值，所有剩余的空间都将是空的并被“保留”在内存中，等待未来的分配。</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/7Hoys8sq0RuDF4-Rgr4WRD4RrImGhtQmzR9P" class="kg-image" alt="7Hoys8sq0RuDF4-Rgr4WRD4RrImGhtQmzR9P" width="800" height="258" loading="lazy"></figure><p>这是关键，数组在访问值方面非常有效。因为所有元素都存储在内存中的连续空间中，这样，计算机就知道在哪里可以找到你请求的信息。</p><p>但是......它有一个缺点😞，因为<strong>这对内存来说不是高效的</strong>。你正在为将来可能不会发生的操作保留内存。<strong>这就是为什么在你事先知道要存储多少个元素的情况下，推荐使用数组的原因。</strong></p><h3 id="--4"><strong><strong>🔧 幕后操作</strong></strong></h3><p>现在你知道什么是数组，什么时候使用它们，以及它们如何存储元素，我们将深入研究关于数组的操作，如插入和删除元素。</p><h4 id="1--1"><strong><strong>1️⃣ 插入元素</strong></strong></h4><p>假设我们有一个大小为 6 的数组，但仍有一个空白空间。我们想在数组的开头（索引 &nbsp;0）插入一个元素 “e”，但是这个位置已经被元素 “a” 占据了。我们应该怎么做？</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/JX8sviJCpwXkWT6mZ4fDIwzSNFDUZ0C8LfrP" class="kg-image" alt="JX8sviJCpwXkWT6mZ4fDIwzSNFDUZ0C8LfrP" width="800" height="480" loading="lazy"></figure><p><strong><strong>要在数组中插入元素</strong></strong>，我们将位于插入点右侧的所有元素向右移动一个索引。元素 “a” 现在将位于索引 1，元素 “b” 将位于索引 2，依此类推……</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/8KFz74m1v5dPBzXGr5IXAvt3a5XFbzL78gVs" class="kg-image" alt="8KFz74m1v5dPBzXGr5IXAvt3a5XFbzL78gVs" width="800" height="476" loading="lazy"></figure><p><strong><strong><strong><strong>💡</strong></strong> 注意</strong>：</strong>你将需要创建一个变量来跟踪包含元素的最后一个索引。在上图中，数组在插入之前被填充到索引 4。这样，你可以确定数组是否已满，以及应该使用什么索引在末尾插入元素。</p><p>这样操作之后，我们就成功插入元素啦。👏</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/VqmOSyTnIvPWbkw9p1PIhenPthaxd3bHxzvS" class="kg-image" alt="VqmOSyTnIvPWbkw9p1PIhenPthaxd3bHxzvS" width="800" height="265" loading="lazy"></figure><h4 id="--5"><strong><strong>⚠️ 等等</strong>！<strong>如果数组是满的呢</strong>？</strong></h4><p>如果数组已满，并且你尝试插入一个元素，会发生什么？ 😱</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/IlI473xQSRYYCMjlcF0YMSOs-Kca2hqqupGk" class="kg-image" alt="IlI473xQSRYYCMjlcF0YMSOs-Kca2hqqupGk" width="800" height="544" loading="lazy"></figure><p>在这种情况下，你需要创建一个新的更大的数组，并手动将所有元素复制到这个新数组中。此操作<strong>非常麻烦</strong>，而且<strong>非常耗时</strong>。 想象一下，如果你有一个包含数百万个元素的数组会发生什么？这可能需要很长时间才能完成。⏳</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/P2q2OaohnsEPDa3KMu3e6eOJaPpw-bpufH95" class="kg-image" alt="P2q2OaohnsEPDa3KMu3e6eOJaPpw-bpufH95" width="734" height="477" loading="lazy"></figure><p><strong><strong><strong><strong>💡</strong></strong> 注意</strong>：</strong>当插入元素非常快时，此规则的唯一例外是，当你在数组<strong>末尾</strong>（位于最后一个元素右侧的索引处）插入一个元素，并且仍有可用空间时。这是在恒定时间 O(1) 内完成的。</p><h4 id="2--1"><strong><strong>2️⃣ 删除元素</strong></strong></h4><p>现在假设你要从数组中删除一个元素。</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/yG5HNXTX7Xj7aXAstjEMU2VNWHkEZXtG9q5z" class="kg-image" alt="yG5HNXTX7Xj7aXAstjEMU2VNWHkEZXtG9q5z" width="753" height="253" loading="lazy"></figure><p>为了保持随机访问的效率（能够极快地通过索引访问数组），元素必须存储在连续的内存空间中。<strong>你不能只是删除元素，并将该空间留空。</strong></p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/bd9KRk22FyVVrW3RJEKvCd8y-VAJQodeABOD" class="kg-image" alt="bd9KRk22FyVVrW3RJEKvCd8y-VAJQodeABOD" width="760" height="320" loading="lazy"></figure><p>你应该将要删除的元素之后的元素向左移动一个索引。</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/G13PaxPTyIQRCBJdh2Ioup-4jM-qlDMnTVd7" class="kg-image" alt="G13PaxPTyIQRCBJdh2Ioup-4jM-qlDMnTVd7" width="755" height="290" loading="lazy"></figure><p>最后，你会得到这个数组👇。如你所见，“b” 已被成功删除。</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/85yhQ9XK19hJ2paBhkb9Cf0-8v52DO0igncc" class="kg-image" alt="85yhQ9XK19hJ2paBhkb9Cf0-8v52DO0igncc" width="753" height="255" loading="lazy"></figure><p><strong><strong><strong><strong>💡 注意</strong></strong></strong>：</strong>由于你需要创建一个变量来跟踪包含元素的最后一个索引（在上图中，是索引 3），你可以使用索引直接删除该元素。</p><h4 id="3-"><strong><strong>3️⃣ 查找一个元素</strong></strong></h4><p>你可以通过三种方式在数组中查找一个元素：</p><ul><li><strong><strong>如果你知道元素的位置</strong>，</strong>就使用索引。</li><li><strong><strong>如果你不知道元素的位置以及数据储存在哪里</strong>，</strong>你可以使用算法来优化搜索，例如二分查找。</li><li><strong><strong>如果你不知道元素的位置以及数据储存在哪里</strong>，</strong>你需要搜索数组中的每个元素，并检查当前元素是否是你要查找的（请参见下面的图表序列）。</li></ul><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/hlrl4kdBl3eM8cT7DXJX7rItWeHzTvrretfG" class="kg-image" alt="hlrl4kdBl3eM8cT7DXJX7rItWeHzTvrretfG" width="772" height="352" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/nFz0jZQu4dtAqv4fauEE-7zVqxtGlKVVfKew" class="kg-image" alt="nFz0jZQu4dtAqv4fauEE-7zVqxtGlKVVfKew" width="766" height="348" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/hxcwNp-VfOem0psPkl26HCLrILCR1mlrdpku" class="kg-image" alt="hxcwNp-VfOem0psPkl26HCLrILCR1mlrdpku" width="767" height="346" loading="lazy"></figure><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/dEd3ArmSERT63fk95KSlKwwCqdwjvUBAOQen" class="kg-image" alt="dEd3ArmSERT63fk95KSlKwwCqdwjvUBAOQen" width="764" height="345" loading="lazy"></figure><h3 id="--6"><strong><strong>👋 总结</strong></strong></h3><ul><li><strong>数组是非常强大的数据结构，</strong>可以存储相同类型的元素。元素的类型和数组的大小是在创建时确定和定义的。</li><li><strong>内存在数组创建后立即分配的</strong>，在你分配值之前它是空的。</li><li><strong>它们的元素位于内存中的连续位置</strong>，因此可以使用索引非常有效地访问它们（随机访问，O(1) = 常数时间）。</li><li><strong><strong>索引是从</strong> 0 开始，</strong>不像我们习惯的从 1 开始。</li><li>在数组的开头或中间<strong>插入元素</strong>涉及向右移动元素。如果数组已满，则创建一个新的更大的数组（效率不高）。在数组末尾插入非常高效，恒定时间 O(1)。</li><li>从数组的开头或中间<strong>删除元素</strong>涉及将所有元素向左移动，以避免在内存中留下空白空间。这保证了元素存储在内存中的连续空间中。在数组末尾删除元素的效率非常高，因为你只删除最后一个元素。</li><li><strong>要查找元素</strong>，你需要检查整个数组，直到找到它为止。如果对数据进行排序，则可以使用二分查找等算法来优化流程。</li></ul><blockquote><em>“</em>总结昨天的经验，努力过好今天，对明天充满希望。最重要的是不要停止思考。”<br><br><em><em>— </em></em>阿尔伯特·爱因斯坦</blockquote><h4 id="--7"><strong><strong>👋 谢谢你</strong>！</strong></h4><p>我希望你喜欢我的文章。❤️<br>在 <a href="https://twitter.com/Estefania_CN_" rel="noopener">Twitter</a> <strong>关注我</strong>，阅读更多文章。😃</p><p>原文：<a href="https://www.freecodecamp.org/news/data-structures-101-arrays-a-visual-introduction-for-beginners-7f013bcc355a/">Data Structures 101: Arrays — A Visual Introduction for Beginners</a>，作者：<a href="https://www.freecodecamp.org/news/author/estefaniacn/">Estefania Cassingena Navone</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 用 JavaScript 实现一个链表 ]]>
                </title>
                <description>
                    <![CDATA[ 在中秋国庆双节同庆的假期里，大家是准备去哪玩，还是想利用这个时间提升自己呢？如果你在学习数据结构，那么你应该了解下链表。假如你并不真正了解 JavaScript，或者不知道如何使用 JavaScript 生成链表 ，那么我推荐你阅读本文。 这篇文章将讨论链表是什么，它与数组有什么不同，以及如何使用 JavaScript来实现 它。咱们开始吧！ 什么是链表 链表格是一种线性数据结构，类似于数组，但不像数组的元素存储在特定的存储器位置或索引中，链表格的每个元素都是一个独立的对象，其中包含一个指针或链接指向列表中的下一个对象。 每一个元素（通常 称为节点）包含两个项目：存储的数据和到下一个节点的链接，这些数据可以是任何有效数据类型 。下面的图表显示： Image of a linked list我们通常使用 “head” 作为链表入口，这个 “head” 是对链表中第一个节点的引用，而链表的最后一个节点指向 null。如果是空链表，则 head 的引用就是 null。 在 JavaScript 中，链表长这样： const list = {     head: {         ]]>
                </description>
                <link>https://www.freecodecamp.org/chinese/news/implementing-a-linked-list-in-javascript/</link>
                <guid isPermaLink="false">5f71a944027c3105323f55f7</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ 数据结构 ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Web开发 ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Chengjun.L ]]>
                </dc:creator>
                <pubDate>Mon, 28 Sep 2020 09:28:24 +0000</pubDate>
                <media:content url="https://chinese.freecodecamp.org/news/content/images/2020/09/photo-1488272690691-2636704d6000.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>在中秋国庆双节同庆的假期里，大家是准备去哪玩，还是想利用这个时间提升自己呢？如果你在学习数据结构，那么你应该了解下链表。假如你并不真正了解 JavaScript，或者不知道如何使用 JavaScript 生成链表 ，那么我推荐你阅读本文。</p><p>这篇文章将讨论链表是什么，它与数组有什么不同，以及如何使用 JavaScript来实现 它。咱们开始吧！</p><h2 id="-">什么是链表</h2><p>链表格是一种线性数据结构，类似于数组，但不像数组的元素存储在特定的存储器位置或索引中，链表格的每个元素都是一个独立的对象，其中包含一个指针或链接指向列表中的下一个对象。</p><p>每一个元素（通常 称为节点）包含两个项目：存储的数据和到下一个节点的链接，这些数据可以是任何有效数据类型 。下面的图表显示：</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/9a130883588449d589b532db930f6ec7~tplv-k3u1fbpfcp-zoom-1.image" class="kg-image" alt="Image of a linked list" title="Image of a linked list" width="600" height="400" loading="lazy"><figcaption>Image of a linked list</figcaption></figure><p>我们通常使用 “head” 作为链表入口，这个 “head” 是对链表中第一个节点的引用，而链表的最后一个节点指向 null。如果是空链表，则 head 的引用就是 null。</p><p>在 JavaScript 中，链表长这样：</p><pre><code class="language-javascript">const&nbsp;list&nbsp;=&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;head:&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;6
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next:&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next:&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;12
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next:&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value:&nbsp;3
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;next:&nbsp;null&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
};</code></pre><h2 id="--1">链表的优点</h2><p>可以很容易地从链表中删除或添加节点，而无需重组整个数据结构。这是它相对于数组的一个优势。</p><h2 id="--2">链表的缺点</h2><ul><li>链表的搜索操作很慢，与数组不同，不允许随机访问数据元素，必须从第一个节点开始按顺序访问节点。</li><li>由于需要储存指针，相较于数组需要更多内存。</li></ul><h2 id="--3">链表的类型</h2><p>链表有以下三种类型：</p><ul><li><strong><strong>单向链表</strong></strong>：每个节点只包含一个指向下一个节点的指针。也就是我们到上面一直在讨论的。</li><li><strong><strong>双向链表</strong></strong>：每个节点包含两个指针，一个指向下一个节点，另一个指向前一个节点。</li><li><strong><strong>循形链表</strong></strong>：循环链表是链表的一种变体，它的最后一个节点指向第一个节点或它之前的任何其他节点，从而形成一个循环。</li></ul><h2 id="-javascript-">用 JavaScript 实现一个表节点</h2><p>前面我们讲到，列表节点包含两项：数据和指向下一个节点的指针。我们可以用 JavaScript 实现如下所示的列表节点：</p><pre><code class="language-javascript">class&nbsp;ListNode&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;constructor(data)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.data&nbsp;=&nbsp;data
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.next&nbsp;=&nbsp;null&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;}
}</code></pre><h2 id="-javascript--1">用 JavaScript 实现一个链表</h2><p>下面的代码展示了使用构造函数实现链表类的方法。注意，如果未传递 “head” 节点，则它将初始化为 null：</p><pre><code class="language-javascript">class&nbsp;LinkedList&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;constructor(head&nbsp;=&nbsp;null)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.head&nbsp;=&nbsp;head
&nbsp;&nbsp;&nbsp;&nbsp;}
}</code></pre><h2 id="--4">将它们合在一起</h2><p>让我们用刚刚创建的类创建一个链表。 首先，我们创建两个表节点，<em>node1</em> 和 <em>node2</em>，以及他们之间的指针：</p><pre><code class="language-javascript">let&nbsp;node1&nbsp;=&nbsp;new&nbsp;ListNode(2)
let&nbsp;node2&nbsp;=&nbsp;new&nbsp;ListNode(5)
node1.next&nbsp;=&nbsp;node2</code></pre><p>接着，我们使用 <em>node1</em> 创建一个链表：</p><pre><code class="language-javascript">let&nbsp;list&nbsp;=&nbsp;new&nbsp;LinkedList(node1)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</code></pre><p>让我们尝试访问刚刚创建的列表中的节点：</p><pre><code class="language-javascript">console.log(list.head.next.data)&nbsp;//returns&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;</code></pre><h2 id="--5">一些链表方法：</h2><p>接下来，我们将为链表实现四个 helper 方法：</p><ol><li>size()</li><li>clear()</li><li>getList()</li><li>getFirst()</li></ol><h3 id="1-size-">1. size()</h3><p>该方法返回链表中存在的节点数：</p><pre><code class="language-javascript">size()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;count&nbsp;=&nbsp;0;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;node&nbsp;=&nbsp;this.head;
&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(node)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count++;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;node&nbsp;=&nbsp;node.next
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;count;
}</code></pre><h3 id="2-clear-">2. clear()</h3><p>该方法清空链表：</p><pre><code class="language-javascript">clear()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;this.head&nbsp;=&nbsp;null
}</code></pre><h3 id="3-getlist-">3. getList()</h3><p>该方法返回链表的最后一个节点：</p><pre><code class="language-javascript">getLast()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;lastNode&nbsp;=&nbsp;this.head;
&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(lastNode)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while&nbsp;(lastNode.next)&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;lastNode&nbsp;=&nbsp;lastNode.next
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;lastNode
}</code></pre><h3 id="4-getfirst-">4. getFirst()</h3><p>该方法返回链表第一个节点：</p><pre><code class="language-javascript">getFirst()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.head;
}</code></pre><p>原文：<a href="https://www.freecodecamp.org/news/implementing-a-linked-list-in-javascript/">How to Implement a Linked List in JavaScript</a>，作者：Sarah Chima Atuonwu</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
