哈希表 - 闭散列

闭散列主要就是需要注意一下“墓碑”的操作,其他的其实都简单。ASL的计算忘了,找了两道题都没算对,这才是我不写的真正原因…代码里是装13用的…

#include<bits/stdc++.h>
using namespace std;

/*
    哈希表:
         散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构。也就是说,它通过把关
         键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。

    两种方式:
        闭散列:若散列函数求出来相同的映射值,则把重复的元素存放在散列表的另一个槽里。
        开散列:把发生冲突的关键码存储在散列表主表之外。 

    闭散列: 
        使用线性探测法举例:对于a、b、c三个数据计算出来的key都是0。在插入的时候应该如下:
        插入: 
            索引:             0           1           2           3
            插入a:                a
            插入b:                b(冲突,后移)
                                            b
            插入c:            c(冲突,后移) 
                                            c(冲突,后移) 
                                                        c
            最终结果:           a           b           c

        查询: 
            查询的时候也是计算value得到key,然后使用和创建时相同的探测方法来向后寻值,直至找到或者遇到空。 
            比如查询b,计算得到key为0,在第0位未寻到b,后移在第一位寻找到了b。
            比如查询d,计算得到key为0,在第0位未寻到d,后移三次之后遇到了空位,说明散列表里没有这个值。

        删除:
            删除的时候不能简单的把数据存放的位置置空。因为这可能影响到其他数据,
            比如我删除b,把第2位置空之后发现。然后我想查找c,通过计算得到key是0,然后向后移动一位遇到空位,返回未找到。
            实际上散列表里是存在c的。所以在删除的时候不能把原数据位置置空,而是设立一个“墓碑”。
            墓碑:标志着这个槽之前存放过数据但现在不再使用了。

        改进插入:
            其实就一个问题,插入的时候如果遇到了墓碑能直接插入吗?答案当然是不能。正确的做法是遇到墓碑后记录
            第一个墓碑所在的位置,然后向后遍历直至遇到真正的空位置,在这个过程中如过存在数据和待插入数据一致。
            则表示数据已存在,插入失败。如果直接循环到了真正的空位置,表面数据不存在,把数据插入第一个墓碑的
            位置,如果全程为出现墓碑,插在当前空位置中。 

    开散列:
        开散列就是数组加链表的形式。从每个索引位置中引出一个链表,用以存储发生冲突时的数据。这个是不需要设置墓碑的。 

    实现:
        下面的实现是基于闭散列的实现。基于开散列的实现请看我的另一篇文章。
        至于说ASL的计算等理论性问题可以去MOOC或者在资料上寻找相关解释,我的CSDN博客整个
        DSA(Data Structure and Algorithm)文集都是侧重于计算机相关专业数据结构与算法课程中遇到的算法的实现。
*/

#define MAX 1010
#define TOMBSTONE 99999999
#define myNull -99999999
class Node
{
    public:
        int *values;
        Node(){ values = new int[MAX]; fill(values, values + MAX, myNull); }
};

//哈希值:最简单的取余法 
int getKey(int val){ return val % 10; }

//冲突解决方案:线性探测法 
int getDis(){  return 1;  }

//插入
bool insert(Node data, int val)
{
    int tomb = -1;
    int key = getKey(val);
    while(data.values[key] != myNull)
    {
        if(data.values[key] == val)
            return false;
        if(data.values[key] == TOMBSTONE && tomb == -1)
            tomb = key;
        key += getDis(); 
    }
    data.values[tomb == -1 ? key : tomb] = val;
    return true;
}

//删除
bool del(Node data, int val)
{
    int key = getKey(val);
    while(data.values[key] != myNull)
    {
        if(data.values[key] == val)
        {
            data.values[key] = TOMBSTONE;
            return true;
        }
        key += getDis();
    }
    return false;
}

//查找
bool getVal(Node data, int val)
{
    int key = getKey(val);
    while(data.values[key] != myNull)
    {
        if(data.values[key] == val)
            return true;
    }
    return false;
}
int main()
{
    Node hashTable;
    insert(hashTable, 1);
    insert(hashTable, 11);
    insert(hashTable, 111);
    cout << hashTable.values[3];
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38206090/article/details/82431541