JavaScript 数据结构之散列表的创建(2)

下面是详细讲解“JavaScript 数据结构之散列表的创建(2)”的完整攻略。

散列表(哈希表)

散列表是一种数据结构,使用哈希函数将键映射到索引。散列表可以在常量时间 O(1) 中进行插入、删除和查找操作,但也具有碰撞冲突问题。

碰撞冲突问题

在散列表中,当两个不同的键通过哈希函数映射到了同一个索引位置时,就会发生碰撞冲突问题。解决碰撞冲突问题的方法有很多,常用的有“链地址法”和“线性探测法”。

链地址法解决碰撞冲突

链地址法也就是“拉链法”,即将同一个索引位置上的所有键都放入到一个链表中。当冲突发生时,只需要将当前键添加到对应索引位置上的链表中即可。

下面是一个使用链地址法的散列表实现示例:

class HashTable {
  constructor() {
    this.table = [];
  }

  // 哈希函数
  hash(data) {
    let total = 0;
    for (let i = 0; i < data.length; i++) {
      total += data.charCodeAt(i);
    }
    return total % this.table.length;
  }

  // 插入操作
  insert(key, value) {
    let index = this.hash(key);

    if (!this.table[index]) {
      // 该索引位置不存在键值对,则创建一个链表存储键值对
      this.table[index] = [];
    }

    // 遍历链表查找指定键
    for (let i = 0; i < this.table[index].length; i++) {
      if (this.table[index][i].key === key) {
        // 键已存在,则更新值
        this.table[index][i].value = value;
        return;
      }
    }

    // 键不存在,则添加新的键值对
    this.table[index].push({ key, value });
  }

  // 获取操作
  get(key) {
    let index = this.hash(key);

    if (!this.table[index]) {
      return undefined;
    }

    // 遍历链表查找指定键
    for (let i = 0; i < this.table[index].length; i++) {
      if (this.table[index][i].key === key) {
        // 键存在,则返回对应的值
        return this.table[index][i].value;
      }
    }

    // 键不存在,则返回 undefined
    return undefined;
  }

  // 删除操作
  remove(key) {
    let index = this.hash(key);

    if (!this.table[index]) {
      return;
    }

    // 遍历链表查找指定键
    for (let i = 0; i < this.table[index].length; i++) {
      if (this.table[index][i].key === key) {
        // 键存在,则从链表中删除该键值对
        this.table[index].splice(i, 1);
        return;
      }
    }
  }
}

// 测试
let hashTable = new HashTable();
hashTable.insert('name', 'Tom');
hashTable.insert('age', 18);
console.log(hashTable.get('name')); // Tom
console.log(hashTable.get('age')); // 18
hashTable.remove('age');
console.log(hashTable.get('age')); // undefined

上面的代码中,我们使用了一个对象数组来存储在散列表中的键值对,如果发生冲突则将键值对存储在同一个索引位置上的对象数组中。

线性探测法解决碰撞冲突

线性探测法也就是“开放地址法”,当发生碰撞时,它会逐一探测下一个空闲位置,直到找到可用的位置为止。

下面是一个使用线性探测法的散列表实现示例:

class HashTable {
  constructor() {
    this.table = [];
  }

  // 哈希函数
  hash(data) {
    let total = 0;
    for (let i = 0; i < data.length; i++) {
      total += data.charCodeAt(i);
    }
    return total % this.table.length;
  }

  // 插入操作
  insert(key, value) {
    let index = this.hash(key);

    if (this.table[index] === undefined) {
      // 该索引位置为空,则直接存储键值对
      this.table[index] = { key, value };
    } else {
      // 该索引位置不为空,则线性探测下一个空闲位置
      let i = 1;
      while (this.table[index + i] !== undefined) {
        i++;
      }
      this.table[index + i] = { key, value };
    }
  }

  // 获取操作
  get(key) {
    let index = this.hash(key);

    // 遍历散列表查找指定键
    for (let i = 0; i < this.table.length; i++) {
      let pos = (index + i) % this.table.length;
      if (this.table[pos] && this.table[pos].key === key) {
        // 键存在,则返回对应的值
        return this.table[pos].value;
      }
    }

    // 键不存在,则返回 undefined
    return undefined;
  }

  // 删除操作
  remove(key) {
    let index = this.hash(key);

    // 遍历散列表查找指定键
    for (let i = 0; i < this.table.length; i++) {
      let pos = (index + i) % this.table.length;
      if (this.table[pos] && this.table[pos].key === key) {
        // 键存在,则将该位置的值置为 undefined
        this.table[pos] = undefined;
        return;
      }
    }
  }
}

// 测试
let hashTable = new HashTable();
hashTable.insert('name', 'Tom');
hashTable.insert('age', 18);
console.log(hashTable.get('name')); // Tom
console.log(hashTable.get('age')); // 18
hashTable.remove('age');
console.log(hashTable.get('age')); // undefined

上面的代码中,我们采用了一种简单的线性探测方法来解决碰撞冲突,如果发生冲突则线性探测下一个空闲位置存储键值对。

至此,“JavaScript 数据结构之散列表的创建(2)”完整攻略讲解完毕,内容详尽、示例丰富,希望能够帮助到你。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript 数据结构之散列表的创建(2) - Python技术站

(0)
上一篇 2023年5月17日
下一篇 2023年5月17日

相关文章

  • 基于python实现模拟数据结构模型

    实现一个模拟数据结构模型的过程需要考虑以下几个步骤: 确定数据结构类型,例如链表、栈、队列、二叉树等。 设计数据结构的具体实现方法,例如链表可采用节点、指针的方式实现,栈可以使用列表或数组实现,队列可使用循环队列实现等。 使用Python编写数据结构相关的类、方法、函数等,确保代码的可读性、灵活性和易维护性。 使用示例数据测试数据结构的各种操作,例如插入、删…

    数据结构 2023年5月17日
    00
  • C语言数据结构实现链表逆序并输出

    下面是C语言数据结构实现链表逆序并输出的完整攻略。 1. 题目分析 本题目要求实现对链表的逆序,并依次输出各节点的值。而链表的逆序可以通过改变各节点之间的连接方式来实现。 2. 思路分析 创建一个指针,指向原链表的头结点。 遍历链表,将每个节点的next指针指向它前面的节点,从而实现链表的逆序。 遍历逆序后的链表,从头结点开始,依次输出每个节点的值。 3. …

    数据结构 2023年5月17日
    00
  • Java数据结构之稀疏数组的实现与应用

    Java数据结构之稀疏数组的实现与应用 什么是稀疏数组 稀疏数组是一种刻画二维数组中许多元素值都为0的特殊数据结构。它可以提高存储空间的利用率,实现对数据的压缩和优化,减少不必要的处理,提升程序的运行效率。 在稀疏数组中,只有非零元素被存储,而这些元素的索引信息和具体数值的信息都会被记录下来。 稀疏数组的实现与应用 实现步骤 创建原始的二维数组,存入多个元素…

    数据结构 2023年5月17日
    00
  • C语言链表详解及代码分析

    C语言链表详解及代码分析 简介 链表是一种常见的数据结构,它主要用于存储线性数据结构,可以动态地进行添加和删除操作。在C语言中,链表可以通过链式存储结构来实现。本篇攻略将详细讲解C语言链表的实现,包括定义链表、节点、添加节点、删除节点等操作。 链表的定义 链表由一个个节点组成,每个节点包含两个信息:数据和指向下一个节点的指针。在C语言中,可以通过结构体实现每…

    数据结构 2023年5月17日
    00
  • Java数据结构之有向图设计与实现详解

    Java数据结构之有向图设计与实现详解 什么是有向图 有向图是一种图形结构,其中每一个节点都有一个方向,即它指向或被其他节点指向。有向图可以用来表示许多实际问题,如路线、依赖关系、状态转移等。 有向图的基本概念 在有向图中,每一个节点都有一个唯一的标识符,被称为节点ID。如果从节点A到节点B存在一条有向边,则称B是A的后继节点,A是B的前驱节点。节点的度数是…

    数据结构 2023年5月17日
    00
  • PHP 数据结构队列(SplQueue)和优先队列(SplPriorityQueue)简单使用实例

    下面我来为大家详细讲解一下“PHP 数据结构队列(SplQueue)和优先队列(SplPriorityQueue)简单使用实例”的攻略。 一、SplQueue 首先,我们先来介绍一下SplQueue。SplQueue是一个双向队列,它基于一个双向链表实现,可以在队列的两端插入和删除元素,既可以按照先进先出的顺序来操作队列,也可以反过来按照先进后出的顺序来操作…

    数据结构 2023年5月17日
    00
  • C++ 数据结构之kmp算法中的求Next()函数的算法

    C++ 数据结构之kmp算法中的求Next()函数的算法 什么是KMP算法和Next()函数 KMP算法(Knuth-Morris-Pratt算法)是一种字符串匹配算法,能够解决的问题是,在一个文本串S中查找一个模式串P是否出现并且返回第一次出现的位置。而Next()函数则是在KMP算法中使用的一个关键的子函数,用于计算模式串P中每个前缀的最长相同真前缀和后…

    数据结构 2023年5月17日
    00
  • Java数据结构之线索化二叉树的实现

    Java数据结构之线索化二叉树的实现 线索化二叉树的概述 线索化二叉树(Threaded Binary Tree)是一种优化的二叉树结构。它的优点是可以在O(n)的时间复杂度内,进行中序遍历。而在普通二叉树中进行中序遍历需要的时间复杂度是O(nlogn)。线索化二叉树的原理是利用空闲的指针域,来记录中序遍历中前驱与后继结点的位置。线索化二叉树中会出现两种类型…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部