数据结构Typescript之哈希表实现详解

数据结构Typescript之哈希表实现详解

什么是哈希表

哈希表(Hash Table)又称为散列表,是一种根据关键字(Key)直接访问内存存储位置的数据结构。通俗的解释就是利用一个哈希函数(Hash Function)将关键字映射到哈希表中的一个位置(索引)来进行访问,从而快速、高效地查找、插入、删除元素。

哈希表的实现

本文将介绍使用Typescript实现一种基于闭散列(Closed Hashing,也称为拉链法Chaining)的简单哈希表。以下为该哈希表的基本实现思路:

  1. 声明一个“链表节点”类,用于存储哈希表中的元素;
  2. 声明一个哈希表类,该类包含以下方法:
  3. hash(key: string): number:基于关键字计算索引值;
  4. put(key: string, value: any): void:向哈希表中插入元素;
  5. remove(key: string): boolean:从哈希表中删除元素;
  6. get(key: string): any:在哈希表中查找指定的元素;
  7. print(): void:输出哈希表的所有元素。

下面让我们详细看一下这些方法的实现。

基于链表节点实现哈希表元素

先声明一个“链表节点”类,用于存储哈希表中的元素,包含元素的关键字(key)和值(value)两个属性:

class Node {
  constructor(public key: string, public value: any) {}
}

基于闭散列实现哈希表

接下来,我们需要根据关键字计算出哈希表元素的索引位置。为了能够直接通过关键字来计算哈希表元素的索引位置,我们需要编写一个哈希函数。这里我们使用最简单的字符串哈希函数——将字符串按字符拆分,并将其所在字符位置的ASCII值相加,得出的结果再取余哈希表的长度,得到哈希表元素的索引位置:

class HashTable {
  private table: any[] = [];

  private loseloseHashCode(key: string): number {
    let hash = 0;
    for (let i = 0; i < key.length; i++) {
      hash += key.charCodeAt(i);
    }
    return hash % this.table.length;
  }
}

在上述代码中,我们通过table数组来存储哈希表,loseloseHashCode函数就是我们的哈希函数。

插入元素

知道如何计算关键字的哈希值之后,我们就可以向哈希表中插入元素了。插入元素有两种情况:

  1. 当哈希表中不存在该关键字时,直接将元素添加到哈希表中;
  2. 当哈希表中已经存在该关键字时,更新该元素的值。

代码如下:

class HashTable {
  // ...

  public put(key: string, value: any): void {
    const position = this.loseloseHashCode(key);
    if (this.table[position] === undefined) {
      this.table[position] = new LinkedList();
    }
    this.table[position].append(new Node(key, value));
  }
}

当table数组中的某个元素为undefined时,说明该位置上未曾插入过元素。我们可以新建一个链表,并将该元素插入到链表的末尾。

当table数组中已经存在某个链表时,说明该位置上已经有元素,我们只需将新元素插入到该链表的末尾即可。

删除元素

删除元素也有两种情况:

  1. 当哈希表中不存在该关键字时,直接返回false;
  2. 当哈希表中存在该关键字时,删除该元素并返回true。

代码如下:

class HashTable {
  // ...

  public remove(key: string): boolean {
    const position = this.loseloseHashCode(key);
    const list = this.table[position];
    if (list !== undefined && !list.isEmpty()) {
      let current = list.getHead();
      while (current !== null) {
        if (current.element.key === key) {
          list.remove(current.element);
          if (list.isEmpty()) {
            this.table[position] = undefined;
          }
          return true;
        }
        current = current.next;
      }
    }
    return false;
  }
}

首先我们和插入操作一样找到该关键字所在的索引位置position以及对应的链表list。然后用循环遍历该链表,找到指定的元素,并将其从链表中删除。最后,我们还需要检查该链表是否为空,如果为空,需要将table数组中该元素的值设为undefined。

查找元素

查找元素也是基于关键字计算出哈希值,然后获取该关键字在哈希表中对应的链表。查找元素的方法只需要顺序遍历该链表,并返回找到的元素即可:

class HashTable {
  // ...

  public get(key: string): any {
    const position = this.loseloseHashCode(key);
    const list = this.table[position];
    if (!list.isEmpty()) {
      let current = list.getHead();
      while (current !== null) {
        if (current.element.key === key) {
          return current.element.value;
        }
        current = current.next;
      }
    }
  }
}

输出哈希表元素

输出哈希表的所有元素非常简单,只需要遍历每个链表并输出其节点元素的key和value属性即可:

class HashTable {
  // ...

  public print(): void {
    for (let i = 0; i < this.table.length; i++) {
      const list = this.table[i];
      if (list !== undefined && !list.isEmpty()) {
        let current = list.getHead();
        while (current !== null) {
          console.log(`${current.element.key} -> ${current.element.value}`);
          current = current.next;
        }
      }
    }
  }
}

示例说明

我们可以尝试向哈希表中插入以下元素:

const hashTable = new HashTable();
hashTable.put("Tom", "programmer");
hashTable.put("Jerry", "designer");
hashTable.put("Mary", "teacher");
hashTable.put("Peter", "student");
hashTable.put("John", "doctor");

然后,我们可以查找哈希表中的某个元素:

hashTable.get("Mary"); // "teacher"

或者从哈希表中删除某个元素:

hashTable.remove("Peter"); // true
hashTable.get("Peter"); // undefined

最后输出整个哈希表中的元素:

hashTable.print();

输出结果如下:

Tom -> programmer
Jerry -> designer
Mary -> teacher
John -> doctor

结论

借助于Typescript强大的类型检查功能,我们可以在代码编写的过程中更加自信和高效地开发出高质量的数据结构。虽然这种实现方式可能不是最高效的,但它值得我们学习和掌握,并为我们日常工作中的需求提供了不同的思路和实现方式。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:数据结构Typescript之哈希表实现详解 - Python技术站

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

相关文章

  • C#常用数据结构和算法总结

    C#常用数据结构和算法总结 数据结构 数组(Array) 数组是一种线性数据结构,它可以在内存中连续地存储相同类型的数据。可以使用索引访问数组中的元素。数组的元素可以是任意类型。 在 C# 中,定义一个数组需要指定数组的类型和数组的大小。例如,定义一个包含 5 个整数的数组: int[] arr = new int[5]; 链表(LinkedList) 链表…

    数据结构 2023年5月17日
    00
  • Golang Mutex互斥锁源码分析

    Golang Mutex互斥锁源码分析 介绍 Golang的Mutex互斥锁机制是一种非常重要的并发控制方式,它可以保证在同一时刻,同一共享资源只能被一个goroutine访问,其他的goroutine必须等待当前访问者释放锁之后才能访问该共享资源。 在使用Mutex机制时,需要进行锁定、解锁等操作,而这一过程是由Mutex的底层实现——sync包来完成的。…

    数据结构 2023年5月17日
    00
  • JavaScript数据结构和算法之二叉树详解

    JavaScript数据结构和算法之二叉树详解 什么是二叉树? 二叉树是一种树形结构,其中每个节点最多有两个子节点:左子节点和右子节点。每个节点都是一个对象,包括属性和方法。节点的属性可能包括值,左节点和右节点。节点的方法可能包括插入和删除。 二叉树的应用场景 二叉树的常用场景包括: 排序算法(二叉排序树); 表达式求值; 线段树; 图形图像学; 数据压缩算…

    数据结构 2023年5月17日
    00
  • JavaScript数据结构Number

    JavaScript数据结构Number 简介 JavaScript中的Number是一种表示数字的数据类型,包括整数和浮点数。Number类型的值是不可变的。 数字类型(Number)的创建 数字类型可以通过直接赋值的方式创建,如: let num = 10; // 整数 let floatNum = 3.14; // 浮点数 另外,JavaScript还…

    数据结构 2023年5月17日
    00
  • Java数据结构专题解析之栈和队列的实现

    Java数据结构专题解析之栈和队列的实现 什么是栈和队列? 在计算机科学中,栈(Stack)和队列(Queue)都是常见的数据结构,用于解决许多问题。它们都是线性数据结构,但它们的元素访问顺序不同。 栈是先进后出(Last In First Out,LIFO)的结构,即最后放入栈中的元素最先被访问。 队列是先进先出(First In First Out,FI…

    数据结构 2023年5月17日
    00
  • C#模拟链表数据结构的实例解析

    C#模拟链表数据结构的实例解析 简介 链表是一种常见的数据结构,它由一系列节点组成,每个节点包含一个数据元素和指向下一个节点的指针。本篇文章将介绍如何使用 C# 来模拟链表数据结构,并通过两个示例展示如何实现链表的操作。 链表的基本结构 链表是由一系列节点组成的,每个节点包含一个数据元素和指向下一个节点的指针。我们可以通过以下代码定义一个链表节点的类: pu…

    数据结构 2023年5月17日
    00
  • 数据结构用两个栈实现一个队列的实例

    下面我将详细讲解“数据结构用两个栈实现一个队列的实例”的完整攻略。 一、背景 在队列和栈这两种数据结构中,都可以实现数据的存储和操作。栈是一种后进先出(LIFO)的数据结构,而队列则是一种先进先出(FIFO)的数据结构。在实际应用中,很多场景需要同时具备队列和栈的特性,且要求效率较高,这时候就需要用两个栈实现一个队列的问题来解决了。 二、解决方案 考虑采用两…

    数据结构 2023年5月17日
    00
  • Go语言数据结构之选择排序示例详解

    Go语言数据结构之选择排序示例详解 什么是选择排序? 选择排序是一种简单的排序算法,它的基本思想是在待排序的数列中选择一个最小(或最大)的元素放到最前面,再在剩下的数列中选择一个最小(或最大)的元素放到已排序序列的末尾,以此类推,直到所有的元素都排序完毕。 其排序的时间复杂度为O(N²),在数据量较小的情况下使用起来非常方便。 选择排序的实现 下面我们来看一…

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