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日

相关文章

  • C++数据结构之文件压缩(哈夫曼树)实例详解

    我来为您详细讲解一下“C++数据结构之文件压缩(哈夫曼树)实例详解”这篇文章的完整攻略: 文章基本信息 标题:C++数据结构之文件压缩(哈夫曼树)实例详解 作者:Coder_XWG 发布时间:2019年12月24日 文章概述 该篇文章主要讲解了哈夫曼树在文件压缩方面的应用。通过实例讲解了如何使用哈夫曼编码将文件进行压缩,以及如何解压缩被压缩的文件,并对文章中…

    数据结构 2023年5月17日
    00
  • php数据结构与算法(PHP描述) 查找与二分法查找

    以下是详细讲解“php数据结构与算法(PHP描述) 查找与二分法查找”的完整攻略。 1. 数据结构与算法简介 数据结构是计算机中存储和组织数据的方式。它涉及到数据的表示、处理和存储方式等。 算法则是完成特定任务的步骤集合。算法设计可以优化计算机程序的效率和速度。 PHP是一种非常流行的服务器端脚本语言,数据结构和算法对web开发者来说非常重要。因此,我们需要…

    数据结构 2023年5月17日
    00
  • C语言数据结构与算法之时间空间复杂度入门

    C语言数据结构与算法之时间空间复杂度入门攻略 1. 什么是时间复杂度和空间复杂度? 在进行算法设计时,我们不仅需要考虑到算法的正确性,还要考虑到算法的执行效率。而衡量算法执行效率的指标主要有两个,即时间复杂度和空间复杂度: 时间复杂度:衡量算法所需时间的度量,通常用“大O”符号来表示。比如,对于n个元素的数组,某些算法需要执行n次操作,这个算法的时间复杂度就…

    数据结构 2023年5月16日
    00
  • 手撕HashMap(二)

    这里再补充几个手撕HashMap的方法 1、remove() remove 方法参数值应该是键值对的键的值,当传入键值对的键的时候,remove 方法会删除对应的键值对 需要利用我们自己先前创建的 hashcodeList 来实现,hashcodeList 存入了所有被使用的 hashcode 值,方便后续的操作 在 put() 中,当添加新的键值对时,就会…

    算法与数据结构 2023年4月18日
    00
  • C语言顺序表的基本结构与实现思路详解

    C语言顺序表的基本结构与实现思路详解 什么是顺序表 顺序表,顾名思义,就是使用连续的存储空间来存储数据元素的线性表。在顺序表中,每一个数据元素都占用一个连续的存储单元,这些存储单元在物理上连续存放,因此,顺序表实际上就是由一个存储数据元素的数组和记录该数组大小的变量组成的。 顺序表的基本结构 顺序表的定义 “`c #define MAXSIZE 100 /…

    数据结构 2023年5月17日
    00
  • C语言如何建立链表并实现增删查改详解

    这是一个比较复杂的问题,需要严谨的思考和详细的解释。下面我将按照以下三个部分,分别介绍: 什么是链表,链表的基本结构和实现方法 如何在C语言中建立链表并实现增删查改 两个示例说明 1. 链表的基本结构和实现方法 链表是一种线性数据结构,每个节点包含两个域:一个数据域和一个指针域。数据域存储节点的数据,指针域存储下一个节点的地址。每个节点都可以独立分配空间,所…

    数据结构 2023年5月17日
    00
  • 数位dp

    数位dp 思想 一般来说,题目是要求在区间\([l,r]\)中符合某一种条件的数的个数 我们用前缀和的思想考虑,分别求出\([1,r]\)和\([1,l-1]\)中数的个数相减即为所求 这里采用记忆化搜索的方式实现 模板 #include<iostream> #include<cstring> #include<vector&g…

    算法与数据结构 2023年4月17日
    00
  • Go 数据结构之二叉树详情

    Go 数据结构之二叉树详情 二叉树是一种树形数据结构,它的每个节点至多只有两个子节点,通常称为左子节点和右子节点。在本文中,我们将介绍二叉树的定义、遍历方法和常见应用场景。 定义 一个二叉树是一个有根树,它的每个节点最多有两个子节点,用左子树和右子树来区分。 在 Go 代码中,可以通过如下结构体定义表示二叉树的节点: type Node struct { L…

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