HomeLập trìnhJavaScriptJavaScript JavaScript

JavaScript JavaScript


Trang chủ:Cấu trúc dữ liệu trong JavaScript – Với các ví dụ về mã,作者:German Cocca

数据结构。

数据 是 一 开发 从业 知道 , , 当 当 你 学习 学习 学习 , , , 觉得 这 个 个 个 个 个 话题 , , 甚至 有些 有些 有些

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]

ngôn ngữ JavaScript原始(内置)非原始(非内置) 两种数据结构。

原始 数据 编程 的 可以 就 数组 数组 ; 非 非 原始 原始 原始 数据 数据 结构 不 数据 , , 你 你

不同 不同 不同 操作 处理 , , , , , , , 当 当 当 当 当 , 用场

让 让 让 , , , , , , , , , , , , , ,

数组是存储在连续内存位置的项目合集。

数组内的每一个元素都可以通过其索引(位置)访问。数组的索引通常从 0 开始,所以在一个包含 4 个元素的数组中,第三个元素嚄紂

const arr = ['a', 'b', 'c', 'd']
console.log(arr[2]) // c

数组的长度4 个元素,我们就可以说这个数组的麿 度丂

const arr = ['a', 'b', 'c', 'd']
console.log(arr.length) // 4

在 一些 , , 个 , , , , , , , 被 被 被 创建 创建 创建 创建

但 JavaScript 的数组并不是这样,在 JavaScript 中,同一数组可以存储任何数据类型的元素,数组长度动态的(也就是说可以按需更改数组长度)。

const arr = ['store', 1, 'whatever', 2, 'you want', 3]

JavaScript 数组可以存储任何数据类型的值,也就意味着可以存储数组。一个包含其他数组的数组被称为多维数组

const arr = [
    [1,2,3],
    [4,5,6],
    [7,8,9],
]

JavaScript 数 组 内置 , , , , 给 给 组 组 组 组 组 组 组 组 组 组 组 组 组 组找到。😉

在 在 在 在 在 , , 尾 尾 最后 最后 最后 最后 最后 最后 最后 最后 最后 最后 最后 最后 最后 最后 最后 最后 最后

但当我们想要在数组的开头或者中间添加或者删除元素的话,添加或删除的这个元素之后的所有元素的索引都会变化。这样会增加计算成本,也是这种数据结的缺点之一。

当 需要 , 结构 , , , , , , 当 在 结构 结构 结构 中 元素 元素 元素)))))

在 JavaScript 中,对象键值对的集合。在其他编程语言中,这种数据结构也被称作映射字典哈希表

一个典型的 JS 对象如下:

const obj = {
    prop1: "I'm",
    prop2: "an",
    prop3: "object"
}

我们使用花括号声明对象,在每一个键之后紧跟一个冒号和对应的值。

Bạn sẽ không bao giờ làm được điều đó nếu bạn muốn thay đổi bản thân?

对象可以存储值和函数。在对象的语境中,我们将值叫作属性,将函数叫作方法。

const obj = {
    prop1: "Hello!",
    prop3: function() {console.log("I'm a property dude!")
}}

访问属性有两种语法,object.propertyobject["property"]。访问方法可以调用object.method()

console.log(obj.prop1) // "Hello!"
console.log(obj["prop1"]) // "Hello!"
obj.prop3() // "I'm a property dude!"

赋值的语法也类似:

obj.prop4 = 125
obj["prop5"] = "The new prop on the block"
obj.prop6 = () => 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"

和 , , , 对象 也 , , 获取 获取 获取 获取 获取 , , , , , ,

对象 是 有 或者 或者 , , , , , , , , , , 对象 条件 条件 条件 条件 条件

可以使用对象来记录有多少人喜欢不同的食物:

const obj = {
    pizzaLovers: 1000,
    pastaLovers: 750,
    argentinianAsadoLovers: 12312312312313123
}

Bạn có thể cho tôi biết bạn đang ở đâu? LIFO 模式(后进先出)。在栈中,不允许按照元素顺序来添加或删除元素,只能遵循 LIFO 模式。

你 , , , 你 你。 , , , , , , , , , , , , , , , , , ,

一叠纸
一叠纸

只要确认元素遵循 Công ty LIFO,那么栈结构就可以派上用场。下面是栈的使用场景:

  • Ứng dụng JavaScript
  • 在各种编程语言中管理函数调用
  • 许多程序提供的撤销/重做功能

有不止一种实现栈的方法,但是最简单的或许是在数组中使用 đẩy 和 pop 方法。如果你仅通过 pop và push 的方法来添加和删除元素,你就遵循了LIFO 模式,用栈的方法操作了数组。

另一个方法是列表,实现如下:

// 为栈的每一个节点创建一个类
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

栈方法的大 O 表示法为:

  • 插入 – O(1)
  • 删除 – O(1)
  • 查找 – O(n)
  • 访问 – O(n)
Đọc thêm  Giải thích phương thức JavaScript Math.random()

队列和栈的运作方式类似,但是元素遵循另一个添加和删除的模式。队列值遵循 FIFO 先进先出模式。在队列中,元素不按照顺序添加或删除,仅遵循 FIFO 模式。

下面 下面 下面 下面 下面 的 , , , , 就 服务 服务 个 个 个 个 个 个 个。FIFO。😉

一队列的顾客
一队列的顾客

队列的使用场景:

  • 后台任务
  • 打印/任务处理

和栈一样,有不止一种实现队列的方式。但是最简单的是在数组中使用 đẩy 和 shift 方法。

如果我们仅使用 push 和 shift 方法来添加和删除元素,我们就在数组中遵循了 FIFO 模式,将数组按照队悗悗悗戗

另一个实现办法是列表,如下:

// 为队列每一个节点的类
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

队列方法的大 O 表示法:

  • 插入 – O(1)
  • 删除 – O(1)
  • 查询 – O(n)
  • 访问 – O(n)

链表是一种以列表存储值的数据结构,在列表中每一个值都被当作为一个节点,每一个节点都通过指针与列表的下一个值关联(若该节点是列表最后一个元素则下一个值为 null)。

Lời bài hát có nghĩa là:单链表双链表。两种链表的运作方式类似,但是在单链表中每一个节点有单指针指向下一个节点,在双链表中,每一个节点有双指针,一个指向下一个节点,一个指向上一个节点

在单链表中每一个节点有单指针
在单链表中每一个节点有单指针
在双链表中每一个节点有双指针
在双链表中每一个节点有双指针

列表的第一个元素被当作,列表的最后一个元素被当作。和数组一样,列表的长度由列表中的元素个数决定。

列表和数组主要不同包括:

  • 列表没有索引,列表中的每一个值仅“知道”其通过指针连接到的值.
  • 因为列表没有索引,所以我们不能随机访问列表中的元素。当我们想要访问一个值,必须通过从头到尾遍历整个列表的方法。
  • 没有索引的好处是添加或删除列表 列表 列表 列表 列表 针指向 针指向 , , , , , , , , , , 的 的 的 的 的 的

和其他所有数据结构一样,可以采用不同的方法来 操作 链表。 通常 通常 会 : : : 、 、 、 、 、 、 )、loại bỏ(删除)和 đảo ngược(反转)。

我们先来看看如何实现单链表,再来看看如何实现双链表。

单链表

完全实现单链表的代码如下:

// 为列表中的每一个节点创建一个类
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 < 0 || index >= 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 < 0 || index > 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 < 0 || index >= 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 < this.length; i++) {
        next = node.next
        node.next = prev
        prev = node
        node = next
      }
      return this
    }
}

单链表的复杂度为:

  • 插入 – O(1)
  • 删除 – O(n)
  • 查找 – O(n)
  • 访问 – O(n)
Đọc thêm  JavaScript cho vòng lặp – Giải thích với các ví dụ

双链表

如 上文 , , 和 个 两 两 由 , , , , , , , , , ,

双 指针 特定 链表 , , , 空间 空间 空间 空间 空间 空间 空间 空间 空间 空间

完全实现双链表的代码类似于:

// 创建列表节点的类
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 < 0 || index >= this.length) return null
        let count, current
        if(index <= 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 < 0 || index > 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
    }
}

双链表的大 O 表示法为:

  • 插入 – O(1)
  • 删除 – O(1)
  • 搜索 – O(n)
  • 访问 – O(n)

树是一种以父子关系相连的节点之间的数据结构,也就是说节点之间相互依赖。

树结构
树结构

树由节点(树的第一个节点)开始,其他所有由根发展出来的节点被称作子节点。树结构最底部的节点没有“后代”,被称为叶节点。树的高度由父子节点相连的层数决定。

和链表及数组不同的地方是,树是非线性的,程序可以在数据结构内选择不同的方向遍历数据,从而得出不同的值。

而在链表或者数组中,程序由一个端始遍历到另一端点,每一次都重复同样的路径。

构成树结构一个重要的要素是仅从父到子连接的节点是合法的。。 亲属 之间 父节点 父节点 我 这样 这样 这样 , , , , , , , , 另 一 种 一 是 是一个根节点

程序中使用树的场景有:

  • DOM 模型
  • 人工智能中的情景分析
  • 操作系统中的文件夹

有不同类型的 , , 的 , , , , , , , , 适用于 适用于 适用于 不同 解决 解决 问题 问题 问题 树 树 树 树 树 是

二叉树

二叉树是每个节点最多只有两个节点的树结构。

二叉树
二叉树

二叉树的一个重要使用场景是搜索。用于搜索的二叉树被称为二叉查找树(BST)

BST 和普通二叉树类似,只是内部的数据结构被排列成易于搜索的结构。

在 BST 中的值是排过序的,所有节点的左子节点的子要小于父节点,所有节点的右子节点的值节玂

二叉查找树
二叉查找树

这样 这样 过序 , , , 每 , , , , 得到 得到 得到 得到 得到 得到 得到 得到 得到 得到 得到 得到 得到 得到 得到 得到 得到值。

插入或者删除值的时候,我们的算法会进行如下步骤:

  • 检查是否存在根节点
  • 如果存在根节点,检查这个需要添加或删除的值是比根节点大还是小
  • 如果 , , , , , , , , , , , , , , , , , ,
  • 如果 , , , , , , , , , , , , , , , , , ,

在 BST 中查找与上述方法类似,但是没有添加或者删除值,取而代之的是与节点比较我们搜寻的值倂

树的大 o 复杂度呈对数(log(n))。。。 , , 结构 , , , , , 我们 我们 我们 搜索 搜索 搜索 搜索 搜索 搜索 搜索 一边 一边 一边 一边 一边 一边 一边 一边 一边的值更多,树结构的搜索效率就会打折扣。

实现 BST 的方法如下:

// 我们创建树的节点
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 < 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 && !found){
            if(value < current.value){
                current = current.left
            } else if(value > 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 && !found){
            if(value < current.value){
                current = current.left
            } else if(value > current.value){
                current = current.right
            } else {
                return true
            }
        }
        return false
    }
}

堆是有特殊规则的树结构。主要有两种形式的堆:最大堆和最小堆。在最大堆中,父节点的值必须比子节点大;在最小堆中,父节点的值必须比子节点小。

Đọc thêm  Cách sử dụng Thực tế tăng cường với JavaScript — một nghiên cứu điển hình
最大堆
最大堆
最小堆
最小堆

堆结构的规则不适用于相邻的两个节点,也就是说在同一层的节点除了必须比自己的父节点大或者小,不需要遵循其他规则。

另外,堆越紧凑越好,也就是每一层都尽可能填满空位,新的节点首先添加到左边。

堆,特别是二进制堆,通常被用来解决优先队列问题,也被运用到知名的算法问题—— 戴克斯特拉算法。

优先队列是一种数据结构,在这种结构中,每一个元素都被关联了优先级,优先级高的元出弝夘

图 是 种 节点 , , , , , , , , , , , , , ,父子关系。

图

图经常被应用于:

  • 社交网络
  • 地理定位
  • 推荐系统

根据节点之间关联的特征,可以把图分成不同的类别:

有向图和无向图

Bạn có thể kiểm soát mọi thứ bằng cách sử dụng các phương tiện truyền thông xã hội.

在 下图 可以 看到 节点 节点 和 和 从 从 可以 可以 可以 , 节点 节点 无定 无定 向 向 着 节点 间

无向图
无向图

你 已经 , , 向 是 完全 的 让 我们 我们 上面 上面 , , , , , , 之间 之间 的 的 的 的 的 是 有 方向 的 的 的

在这幅图中,你可以由节点 A 到节点 B,但是不能从节点 B 到节点 A。

有向图
有向图

加权图和非加权图

如果 节点 连接 , , , 称 为。。 分配 给 给 了 节点 节点 之间 , , , , , ,

在下面的例子中我们可以看到,节点 0 和节点 4 之间连接的权重是 7;而节点 3 和节点 1 之悯 4 之间皚

加权图
加权图

想要 想要 , , , , , , , , , 告诉 告诉 告诉 告诉 告诉 告诉 多 多 多

加权图 加权图 加权图 加权图 加权图 , , , , 道路 , , , , 的 的 物理 物理 物理 物理 物理 物理 物理 物理 物理

加权图被大量应用在定位系统
加权图被大量应用在定位系统

你 已经 , 即 节点 连接 没有 , , , 的 的 的 没有 没有 额外 的 , , , , , ,

如何表达图

在编码图的时候,主要可以使用两种方法:邻接矩阵邻接列表。让我们分别看看这两种方法的优缺点。

邻接矩阵是一个二维结构代表图的节点和节点之间的连接。

如果我们使用这个的例子:

Untitled-Diagram.drawio

我们的邻接矩阵会是这个样子:

Một b C Đ.
Một 1 1
b 1 1
C 1 1
Đ. 1 1

矩阵 可以 , , , , , , , , , , , , , , , , , , , ,是 0,则表示没有联系。

这个表格可以用简单的二维数组来表示:

[
    [0, 1, 1, 0]
    [1, 0, 0, 1]
    [1, 0, 0, 1]
    [0, 1, 1, 0]
]

邻接列表可以使用键值对结构来表示,键代表节点值代表对应节的连接

上面的例子,用邻接列表可以表达为:

{
    A: ["B", "C"],
    B: ["A", "D"],
    C: ["A", "D"],
    D: ["B", "C"],
}

每一个节点为一个键,对应的值是与节点相连接的节点组成的数组。

这 就 矩阵 的 需要 需要 , , 添加 添加 , , , , , ; 需要 需要 需要 需要 需要

假设要在我们的图里添加一个新的节点:

Untitled-Diagram.drawio-1

如果要用矩阵来表达的话,我们需要添加一个全新的列和行:

Một b C Đ. e
Một 1 1
b 1 1 1
C 1 1
Đ. 1 1
e 1

但是在列表中,我们只需要在 B 的连接数组中添加一个值,以及再添加一个代表 E 的键值对冱够:

{
    A: ["B", "C"],
    B: ["A", "D", "E"],
    C: ["A", "D"],
    D: ["B", "C"],
    E: ["B"],
}

现在 现在 需要 验证 和 和 , , , , , , , , , , , , , , , , 哪个

Một b C Đ. e
Một 1 1
b 1 1 1
C 1 1
Đ. 1 1
e 1

但 但 , , , 遍历 遍历 遍历 遍历 遍历 遍历 遍历 有 有 通过 通过 这 这 个 个

邻接列表的完全实现如下,我们把图限定在无向和无权重,来简化代码:

// 为图创建一个类
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 => v !== node2)
        this.adjacencyList[node2] = this.adjacencyList[node2].filter(v => 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' ]
//     }
// }

以上 就 内容 这 篇 软件 和 和 和 和 的 数据 数据 结构。。 数据 数据 数据 数据 结构 结构

虽然 刚 这个 , , , , , , , , , 当 当 当 当 当 一 一 一 一

希望你享受阅读这篇文章,并且从中受益。你可以在 LinkedIn 或者 Twitter 上关注我。

我们下篇文章见!

3cd





Zik.vn – Biên dịch & Biên soạn Lại

spot_img

Create a website from scratch

Just drag and drop elements in a page to get started with Newspaper Theme.

Buy Now ⟶

Bài viết liên quang

DMCA.com Protection Status