• 15.模拟散列表 哈希表


     

     

    哈希表的时间复杂度近似O(1)

    什么情况下需要用到哈希表

    把一个庞大的值域,映射到一个较小的(10 ^ 5 ~ 10 ^ 6左右)值域

     之前的离散化是一种极其特殊的哈希方式,之前的离散化需要保序的,需要保证单调递增

    现在说的是一般意义的哈希

     定义一个哈希函数h()

    使得h(x)的值域属于0 ~ 10 ^ 5, x的取值范围是 -10 ^ 9 ~ 10 ^ 9

    一般情况下,哈希函数可以直接取模

     然后还需要处理一下冲突的问题

    如果两个不同的数经过哈希函数之后,映射成了相同的一个数如何解决

    按照处理冲突的方式,把哈希表分为两种,开放寻址法和拉链法

    拉链法:

    图论里面存点的时候,用到的存储结构和拉链法相同

    首先开个一维数组,来存储所有的哈希值

    每一个槽上拉一条链(单链表),来存储这个槽上当前有的所有数

     一般情况下,算法题目不需要在哈希表中删除元素。一般只有添加和查找两个操作

    如果真要删除,不是真正的把这个元素从表中删除。可以再开一个数组,打一个标记,表示这个点被删除了

    拉链法代码

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 //拉链法
     4 const int N = 100003;
     5 //取模的时候要取质数,而且要离2的整次幂尽可能远
     6 //这样冲突的概率最小
     7 int h[N], e[N], ne[N], idx;
     8 //h数组是槽,其余和单链表一样
     9 void insert(int x) { //插入操作
    10     int k = (x % N + N) % N;
    11     //k是哈希值
    12     e[idx] = x;
    13     ne[idx] = h[k]; //头插法
    14     h[k] = idx;
    15     idx++;
    16 }
    17 bool find(int x) { //查询操作
    18     int k = (x % N + N) % N;
    19     for (int i = h[k]; i != -1; i = ne[i]) {
    20         if (e[i] == x) {
    21             return true;
    22         } 
    23     }
    24     return false;
    25 }
    26 int main() {
    27     memset(h, -1, sizeof(h)); //把所有槽清空,单链表的空指针用-1表示
    28     int n;
    29     cin >> n;
    30     while (n--) {
    31         string op;
    32         int x;
    33         cin >> op;
    34         if (op == "I") {
    35             cin >> x;
    36             insert(x);
    37         } else {
    38             cin >> x;
    39             if (find(x)) { //如果能找到x这个数的话
    40                 cout << "Yes" << endl;
    41             } else {
    42                 cout << "No" << endl;
    43             }
    44         }
    45     }
    46     return 0;
    47 }

    开放寻址法:

    只开一维数组

    这个一维数组的长度,经验上看,要开到题目数据范围的2 ~ 3倍

    开放寻址法处理冲突的思路是:冲突了就往后找,直到空了

     开放寻址法代码

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N = 200003, null = 0x3f3f3f3f;
     4 //如果数组上的数是null的话,表示这个位置上是空
     5 //这个数只要不在题目的数据范围内就好了
     6 int h[N];
     7 int find(int x) {
     8     //如果x在哈希表中已经存在的话,返回x所在的位置
     9     //如果x在哈希表中不存在的话,返回x应该存储的位置
    10     int k = (x % N + N) % N;
    11     while (h[k] != null && h[k] != x) {
    12         k++;
    13         if (k == N) {
    14             k = 0;
    15         }
    16     }
    17     return k;
    18 }
    19 int main() {
    20     memset(h, 0x3f, sizeof(h));
    21     int n;
    22     cin >> n;
    23     while (n--) {
    24         string op;
    25         int x;
    26         cin >> op >> x;
    27         if (op == "I") {
    28             int k = find(x);
    29             h[k] = x; 
    30         } else {
    31             int k = find(x);
    32             if (h[k] != null) {
    33                 cout << "Yes" << endl;
    34             } else {
    35                 cout << "No" << endl;
    36             }
    37         }
    38     }
    39     return 0;
    40 }
  • 相关阅读:
    【转】算法的时间复杂度
    FFT 物理意义(转)
    【转】FIR学习1
    【转】DFT DTFT DFS FFT的关系
    【转】TCL中的数组
    【转】setup time和hold time的周期问题(slack)
    【转】TCL语法简介
    【转】亚稳态分析
    ubuntu下Samba服务器搭建
    第一次生成uImage出现的问题解决
  • 原文地址:https://www.cnblogs.com/fx1998/p/13304801.html
Copyright © 2020-2023  润新知