哈希闭散列实现

在上一篇文章中,我们已经对哈希的基础有了一个大概的认识,但是对其实现还没有做具体的解释,在这篇文章中,我们将对这一部分做出一个详细的解释。
有关哈希基础,
请参考上篇https://blog.csdn.net/aaronlanni/article/details/79701843
一、实现静态的哈希表
这里写图片描述
下面,将给出静态实现:

//静态
#define MAX_SIZE 10

typedef enum State{ EMPTY, DETELE, EXIST };

template<class K>
struct Elem
{
    K _key;
    State _state;
};

template<class K,bool IsLine=true>
class HashTable
{
public:
    HashTable()
    {
        //清空每个位置
        for (int i = 0; i < MAX_SIZE; ++i)
        {
            _hashtable[i]._state = EMPTY;
        }
        _size = 0;
    }
    //插入元素
    bool Insert(const K&key)
    {
        //负载因子
        if (_size * 10 / MAX_SIZE>7)
            return false;
        size_t HashAdder = Func(key);
        size_t stateAdder = HashAdder;
        size_t i = 0;
        //找空位置
        while (_hashtable[HashAdder]._state != EMPTY)
        {
            if (_hashtable[HashAdder]._state == EXIST&&_hashtable[HashAdder]._key == key)
                return false;

            if (IsLine)
                LineCheck(HashAdder);
            else
                SecondCheck(HashAdder, i++);
            if (HashAdder == stateAdder)
                return false;
        }
        //插入元素
        _hashtable[HashAdder]._key = key;
        _hashtable[HashAdder]._state = EXIST;
        ++_size;
        return true;
    }
    //查找元素
    int Find(const K&key)
    {
        //在哈希表中找对应的位置
        size_t HashAdder = Func(key);
        size_t i = 0;
        //找空位置
        while (_hashtable[HashAdder]._state != EMPTY)
        {
            if (_hashtable[HashAdder]._key == key)
                return _hashtable[HashAdder]._key;

            if (IsLine)
                LineCheck(HashAdder);
            else
                SecondCheck(HashAdder, i++);
        }
        return -1;
    }
    //删除元素
    bool DElete(const K&key)
    {
        size_t HashAdder = Func(key);
        int ret = Find(key);
        if (-1 != ret)
        {
            _hashtable[HashAdder]._state = DETELE;
            --_size;
            return true;
        }
        return false;
    }
    size_t Size()
    {
        return _size;
    }
    bool Empty()
    {
        return _size == 0;
    }
private:
    //线性探测
    void LineCheck(size_t& HashAdder)
    {
        ++HashAdder;
        if (HashAdder >= MAX_SIZE)
            HashAdder = 0;
    }
    //二次探测
    void SecondCheck(size_t HashAdder,size_t i)
    {
        HashAdder = HashAdder + ((i << 1) + 1);
        if (HashAdder >= MAX_SIZE)
            HashAdder %= MAX_SIZE;
    }
private:
    //哈希函数
    size_t Func(const K&key)
    {
        return key%MAX_SIZE;
    }
private:
    Elem<K> _hashtable[MAX_SIZE];
    size_t _size;
};

二、实现动态的哈希表
在静态哈希表的基础上,由于利用静态存储,很容易将哈希表存满,因此,利用动态的哈希表,从而可以实现不断的给哈希中存储元素,但是在上面的基础上,我们难免还会想到,在哈希中,我们不仅仅是对整型数值的存储,在必要的时候,我们还需要存储字符串,因此在对于字符串的存储中,我们对哈希地址的计算便是一个大问题,因此将字符串转换为整数,然后对其哈希地址进行计算即可。
(对于有关字符串转整数,可以采取两种措施:1、对其字符串取地址,从而可以取得字符串的整数形式2、利用字符串转整数的函数,同时在此基础上,且利用类与特化从而实现字符串的转换即可)
在实现动态的哈希表之时,利用除留余数法即可。
基本实现如下所示:
comm.hpp

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<string.h>
#include<iostream>
using namespace std;
// 使用素数表对齐做哈希表的容量,降低哈希冲突
const int _PrimeSize = 28;
static const unsigned long _PrimeList[_PrimeSize] =
{
    53ul, 97ul, 193ul, 389ul, 769ul,
    1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
    49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
    1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
    50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
    1610612741ul, 3221225473ul, 4294967291ul
};
//除留余数法
size_t GetNextPrime(size_t num)
{
    for (int i = 0; i < _PrimeSize; ++i)
    {
        if (_PrimeList[i] > num)
            return _PrimeList[i];
    }

    //走到最后,仍然没有找到
    return _PrimeList[_PrimeSize - 1];
}
static size_t BKDRHash(const char * str)
{
    unsigned int seed = 131; // 31 131 1313 13131 131313
    unsigned int hash = 0;
    while (*str)
    {
        hash = hash * seed + (*str++);
    }
    return (hash & 0x7FFFFFFF);
}
//转换函数(整数)
template<class K>
class KeyToIntDef
{
public:
    size_t operator()(const K&key)
    {
        return key;
    }
};
//字符串,需要特化

class StringToInt
{
public:
    size_t operator()(const string&  key)
    {
        return BKDRHash(key.c_str()); //key.c_str()将其
    }
};

hashtable.hpp

//可以存取字符串
#include"Common.hpp"

//如果需要存取字符串,则需要在求取哈希地址的时候,需要转换,利用仿函数

template<class K>
struct Elem
{
    K _key;
    State _state;
};

template<class K, class KeyToInt = KeyToIntDef<int>, bool IsLine = true>
class HashTable
{
public:
    HashTable(size_t capacity = 10)
    {
        capacity = GetNextPrime(capacity);//获得的哈希表的长度
        _hashtable = new Elem<K>[capacity];
        _capacity = capacity;
        for (size_t i = 0; i < _capacity; ++i)
            _hashtable[i]._state = EMPTY;
        _size = 0;
    }
    //插入元素
    bool Insert(const K&key)
    {
        CheckCapacity();
        size_t HashAdder = Func(key);
        size_t stateAdder = HashAdder;
        size_t i = 1;
        //找空位置
        while (_hashtable[HashAdder]._state != EMPTY)
        {
            if (_hashtable[HashAdder]._state == EXIST&&_hashtable[HashAdder]._key == key)
                return false;

            if (IsLine)
                LineCheck(HashAdder);
            else
                SecondCheck(HashAdder, i++);
            if (HashAdder == stateAdder)
                return false;
        }
        //插入元素
        _hashtable[HashAdder]._key = key;
        _hashtable[HashAdder]._state = EXIST;
        ++_size;
        return true;
    }
    //查找元素
    int Find(const K&key)
    {
        //在哈希表中找对应的位置
        size_t HashAdder = Func(key);
        size_t i = 1;
        //找位置
        while (_hashtable[HashAdder]._state != EMPTY)
        {
            if (_hashtable[HashAdder]._state == EXIST)
            {
                if (_hashtable[HashAdder]._key == key)
                    return HashAdder;
            }

            if (IsLine)
                LineCheck(HashAdder);
            else
                SecondCheck(HashAdder, i++);
        }

        return -1;
    }

    //删除元素
    bool DElete(const K&key)
    {
        size_t HashAdder = Func(key);
        int ret = Find(key);
        if (-1 != ret)
        {
            _hashtable[HashAdder]._state = DETELE;
            --_size;
            return true;
        }
        return false;
    }

    size_t Size()
    {
        return _size;
    }
    bool Empty()
    {
        return _size == 0;
    }

    ~HashTable()
    {
        if (_hashtable)
        {
            _capacity = 0;
            _size = 0;
            delete[] _hashtable;
        }
    }
private:
    //交换函数
    void Swap(HashTable<K,KeyToInt,IsLine>& ht)
    {
        swap(_hashtable, ht._hashtable);
        swap(_size, ht._size);
        swap(_capacity, ht._capacity);
    }
    //增容函数
    void CheckCapacity()
    {
        if (_size * 10 / _capacity >= 5)
        {
            size_t newCapacity = GetNextPrime(_capacity);
            HashTable<K,KeyToInt,IsLine> newHt(newCapacity);//创建新的哈希表
            //搬移元素
            for (size_t i = 0; i < _capacity; ++i)
            {
                if (_hashtable[i]._state == EXIST)
                    newHt.Insert(_hashtable[i]._key);
            }
            Swap(newHt);
        }
    }
    //线性探测
    void LineCheck(size_t& HashAdder)
    {
        ++HashAdder;
        if (HashAdder >= _capacity)
            HashAdder = 0;
    }
    //二次探测
    void SecondCheck(size_t HashAdder, size_t i)
    {
        HashAdder = HashAdder + ((i << 1) + 1);
        if (HashAdder >= _capacity)
            HashAdder %= _capacity;
    }
private:
    size_t Func(const K&key)
    {
        return KeyToInt()(key)%_capacity;
    }
private:
    Elem<K> * _hashtable;
    size_t _size;
    size_t _capacity;
};

有关闭散列的有关知识,大概就这么多了,希望大家一起进步!!!

只有不停的奔跑,才能不停留在原地!!!

猜你喜欢

转载自blog.csdn.net/aaronlanni/article/details/80229608