C++数据结构之哈希表的实现

以下是详细的讲解:

C++数据结构之哈希表的实现

哈希表的概念

哈希表是一种能够实现快速查找的散列表,通过将关键字映射到哈希表中的一个位置来实现快速查找。哈希表的查询、删除时间复杂度为O(1),操作效率非常高,所以常常被用来对大量数据进行检索。

哈希表的实现

哈希函数

哈希函数的主要作用就是将任意长度的输入数据转化为固定长度的散列值,一般采用对关键字进行取模的方式,也可以使用其他算法。哈希函数的设计对哈希表的性能有着至关重要的作用。

例如,下面是一个简单的哈希函数实现:

int hashFunc(int key, int tableSize){
    return key % tableSize;
}

其中,key是关键字,tableSize是哈希表的大小,hashFunc函数将key值取模作为哈希值返回。

冲突解决

当不同的关键字映射到同一个哈希值时,就发生了冲突。哈希表的冲突解决方法有很多种,这里介绍两种比较常用的方法。

链表法

链表法是一种将冲突的关键字以链表的形式串联起来,存放到同一个哈希值对应的位置上。

例如,以下是一个简单的链表法哈希表实现:

struct Node{
    int key;
    Node* next;
    Node(int k) : key(k), next(nullptr) {}
};

class HashTable{
private:
    int tableSize;
    vector<Node*> hashTable;
    int hashFunc(int key){
        return key % tableSize;
    }
public:
    HashTable(int size){
        tableSize = size;
        hashTable.resize(tableSize);
    }

    void insert(int key){
        int hashValue = hashFunc(key);
        if(hashTable[hashValue] == nullptr){
            hashTable[hashValue] = new Node(key);
        } else {
            Node* currentNode = hashTable[hashValue];
            while(currentNode->next != nullptr){
                currentNode = currentNode->next;
            }
            currentNode->next = new Node(key);
        }
    }

    bool search(int key){
        int hashValue = hashFunc(key);
        Node* currentNode = hashTable[hashValue];
        while(currentNode != nullptr){
            if(currentNode->key == key){
                return true;
            }
            currentNode = currentNode->next;
        }
        return false;
    }

    void remove(int key){
        int hashValue = hashFunc(key);
        Node* currentNode = hashTable[hashValue];
        Node* prevNode = nullptr;
        while(currentNode != nullptr){
            if(currentNode->key == key){
                if(prevNode == nullptr){
                    hashTable[hashValue] = currentNode->next;
                } else {
                    prevNode->next = currentNode->next;
                }
                delete currentNode;
                return;
            }
            prevNode = currentNode;
            currentNode = currentNode->next;
        }
        return;
    }
};

在上面的实现中,我们将哈希值相同的关键字以链表的形式进行存储,这样,在查找关键字的时候,如果哈希值相同,我们就沿着链表依次查找,直到找到目标位置或者链表遍历完毕。

开放定址法

开放定址法是一种将冲突的关键字插入到哈希表中空闲的地址上,常见的几种方式有线性探测、二次探测和双重散列等。

例如,以下是一个简单的线性探测哈希表实现:

class HashTable{
private:
    int tableSize;
    vector<int> hashTable;
    int hashFunc(int key){
        return key % tableSize;
    }
public:
    HashTable(int size){
        tableSize = size;
        hashTable.resize(tableSize, -1);
    }

    void insert(int key){
        int hashValue = hashFunc(key);
        int i = 0;
        while(hashTable[(hashValue + i) % tableSize] != -1){
            i++;
        }
        hashTable[(hashValue + i) % tableSize] = key;
    }

    bool search(int key){
        int hashValue = hashFunc(key);
        int i = 0;
        while(hashTable[(hashValue + i) % tableSize] != key && hashTable[(hashValue + i) % tableSize] != -1){
            i++;
        }
        if(hashTable[(hashValue + i) % tableSize] == key){
            return true;
        } else {
            return false;
        }
    }

    void remove(int key){
        int hashValue = hashFunc(key);
        int i = 0;
        while(hashTable[(hashValue + i) % tableSize] != key && hashTable[(hashValue + i) % tableSize] != -1){
            i++;
        }
        if(hashTable[(hashValue + i) % tableSize] == key){
            hashTable[(hashValue + i) % tableSize] = -1;
        }
        return;
    }
};

在上面的实现中,我们使用线性探测的方式解决了冲突问题,具体来说,在插入关键字的时候,如果目标位置已经有了其他关键字,我们就把目标位置后继的位置再判断一遍,直到找到一个空闲的地址,然后将关键字插入到该位置。在查找和删除时,我们同样需要进行连续的查找操作直到查找到目标位置或者发现该位置已经被占用了。

示例说明

链表法哈希表

以下是一个简单的用链表法实现的哈希表示例:

HashTable hashTable(10);
hashTable.insert(1);
hashTable.insert(12);
hashTable.insert(23);
hashTable.insert(14);
hashTable.insert(35);

cout << hashTable.search(12) << endl;
cout << hashTable.search(18) << endl;

hashTable.remove(14);

cout << hashTable.search(14) << endl;

运行结果如下:

1
0
0

在上面的示例中,我们首先创建了一个哈希表,然后插入了5个不同的关键字。然后我们分别查找哈希表中是否包含12和18这两个关键字,最后删除14这个关键字,然后再次检查哈希表中是否包含14这个关键字。可以看到,我们使用链表法实现的哈希表能够正常地进行插入、查找、删除操作,并且在删除关键字后,能够正确地返回“false”。

开放定址法哈希表

以下是一个简单的用开放定址法实现的哈希表示例:

HashTable hashTable(10);
hashTable.insert(1);
hashTable.insert(12);
hashTable.insert(23);
hashTable.insert(14);
hashTable.insert(35);

cout << hashTable.search(12) << endl;
cout << hashTable.search(18) << endl;

hashTable.remove(14);

cout << hashTable.search(14) << endl;

运行结果如下:

1
0
0

在上面的示例中,我们同样首先创建了一个哈希表,然后插入了5个不同的关键字。然后我们同样分别查找哈希表中是否包含12和18这两个关键字,最后删除14这个关键字,然后再次检查哈希表中是否包含14这个关键字。可以看到,我们使用开放定址法实现的哈希表同样能够正常地进行插入、查找、删除操作,并且在删除关键字后,能够正确地返回“false”。

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

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

相关文章

  • Java 数据结构与算法系列精讲之哈希算法实现

    Java 数据结构与算法系列精讲之哈希算法实现 什么是哈希算法? 哈希算法是一种能将任意长度的消息压缩到某一固定长度的消息摘要的算法。 通过哈希算法,我们可以将一个任意的大数据量压缩成一段固定长度的数据,这个数据的长度通常比较小,相对于原数据的大小来说,要小得多。哈希算法的压缩特性使得它经常用来进行信息摘要、数据校验、唯一识别等功能,可以很大程度上提高数据的…

    数据结构 2023年5月17日
    00
  • C++数据结构之单链表的实现

    C++数据结构之单链表的实现可分为以下步骤: 1. 定义链表节点类 链表节点类需要包含两个成员变量,一个是存储数据的变量,另一个是指向下一个节点的指针变量。同时,需要实现构造函数和析构函数。 class Node{ public: int data; // 存储节点数据 Node* next; // 指向下一个节点的指针 Node(int data):dat…

    数据结构 2023年5月17日
    00
  • C语言 结构体数组详解及示例代码

    C语言 结构体数组详解及示例代码 结构体是C语言中最为基础的数据结构之一,它可以将多个数据类型组合成一个整体,方便地进行访问和管理。而结构体数组则是将多个相同结构体类型的变量按照一定规律排列在一起的一种数据结构。本文将详细讲解C语言中结构体数组的使用方法及示例代码。 定义结构体 首先,我们需要定义一个结构体类型。结构体类型需要指定名称、成员变量及其数据类型:…

    数据结构 2023年5月17日
    00
  • java编程队列数据结构代码示例

    下面是“Java编程队列数据结构代码示例”的完整攻略。 什么是队列 队列是一种有序的数据结构,特点是先进先出(FIFO)。队列中不管是插入操作还是删除操作,都是在队列的两端进行的,插入操作在队列的尾部进行,删除操作在队列的头部进行。队列的一个重要用途是在计算机的操作系统中,实现进程和所有需要等待资源的实体之间的交互。 队列的实现 队列数据结构可以采用数组或链…

    数据结构 2023年5月17日
    00
  • C语言数据结构之单链表存储详解

    C语言数据结构之单链表存储详解 什么是单链表 链表是一种非顺序存储的数据结构,其每个节点都保存下一个节点的地址。单链表是最简单的链表,每个节点只包含下一个节点的地址。 单链表节点的定义 单链表的节点定义一般包括两个部分:数据域和指针域。数据域存放节点的数据,指针域存放下一个节点的地址。 以下是单链表节点的定义: typedef struct node { i…

    数据结构 2023年5月17日
    00
  • Java concurrency集合之LinkedBlockingDeque_动力节点Java学院整理

    Java Concurrency集合之LinkedBlockingDeque_动力节点Java学院整理 LinkedBlockingDeque是什么? LinkedBlockingDeque是java.util.concurrent包下一个双向阻塞队列,用于在多线程的环境中处理元素序列,它支持在队列两端添加和移除元素。LinkedBlockingDeque可…

    数据结构 2023年5月17日
    00
  • C#数据结构与算法揭秘二 线性结构

    C#数据结构与算法揭秘二 线性结构 线性结构是指数据元素之间一对一的关系,即数据元素之间存在一个前驱和一个后继。一般有两种基本形式:线性表和栈、队列。 线性表 线性表是由同类型数据元素构成有序序列的线性结构,常被用于实现基于数组的数据结构,如向量、矩阵等。 线性表可以分为顺序表和链表两种。 顺序表(Sequence List):是把线性表的元素按照顺序存储在…

    数据结构 2023年5月17日
    00
  • NDK 数据结构之队列与栈等的实现

    NDK 数据结构之队列与栈等的实现 引言 Android NDK 是 Android 开发工具包的一部分,可以用 C 和 C++ 编写应用程序和库。NDK 带来了许多好处,例如可以针对不同的平台进行优化,可以通过调用底层 C/C++ 库实现更高效的算法等。 在本篇文档中,我们将探讨如何使用 NDK 实现一些基础的数据结构,包括队列、栈等等。 队列的实现 队列…

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