哈希初步结构:闭散列与开散列(代码部分)

引子:哈希表作为一种重要的,那他余数取模法的闭散列与开散列在底层是如何实现的呢?今天我们来一探究竟!由于前一篇我们已经讲过什么是闭散列与开散列,所以我们不再过多赘述,直接进入主题,上代码!(代码中已经包含了测试代码)

优化:我们实现的并不排除全部数据集中在一个桶内,这样时间复杂度看,没有达到我们想要的效果,对此,我们可以用vector<红黑树>来进行封装,这样查找的次数会被限制在log_2 N,详见红黑树,请看我前二篇!

前提:由于哈希要求key能转换为整形,对于string类我们需要用到特化,来进行处理!如下:

#pragma once
#include<iostream>
#include<string>
#include<vector>

using namespace std;



//key要求有转整形的作用
template<class K>
class Hash_to_int
{
public:
	size_t operator()(const K& key)
	{
		return (size_t)key;
	}
};

//对于string类的转换--特化
template<>
class Hash_to_int<string>
{
public:
	//仿函数
	size_t operator()(const string& key)
	{
		size_t numi = 0;
		for (auto e : key)
		{
			numi *= 131;
			numi += e;
		}
		return numi;
	}
};

闭散列:

//闭散列
namespace hash_close
{
    enum State
    {
        FULL,
        EMPTY,
        DELETE
    };

    template<class K,class V>
    class hashData
    {
    public:
        pair<K, V> _kv;
        State _state = EMPTY;
    };


    template<class K,class V,class hash= Hash_to_int<K>>
    class hashTable
    {
    public:
        typedef hashData<K, V> Data;
        hashTable()
            :_number(0)
        {
            _table.resize(10);
        }
        
        //除留余数法--(常用)

        //寻找
        Data* Find(const K& key)
        {
            hash to_int;

            size_t numi = to_int(key) % _table.size();

            while (_table[numi]._state != EMPTY)
            {
                if (_table[numi]._state!=DELETE && _table[numi]._kv.first==key)
                {
                    return &_table[numi];
                }
                numi++;
                numi %= _table.size();
            }
            return nullptr;
        }

        //删除
        bool Erase(const K&key)
        {
            Data* cmp = Find(key);
            if (cmp)
            {
                cmp->_state = DELETE;
                return true;
            }
            else
                return false;
        }


        //insert
        bool insert(const pair<K, V>& kv)
        {
            //在原有的数据里面已经有这个了,要确保唯一性
            if (Find(kv.first))
                return false;

            //扩容问题--负载因子
            int n = _number * 10 / _table.size();
            if (n >= 7)
            {
                hashTable<K, V, hash> newTable;
                newTable._table.resize(_table.size() * 2);
                for (size_t i = 0; i < _table.size(); i++)
                {
                    if (_table[i]._state == FULL)
                    {
                        newTable.insert(_table[i]._kv);
                    }
                }
                _table.swap(newTable._table);
            }

            hash to_int;
            size_t numi = to_int(kv.first) % _table.size();
            while (_table[numi]._state == FULL)
            {
                numi++;
                numi %= _table.size();
            }

            _table[numi]._kv = kv;
            _table[numi]._state = FULL;
            _number++;
            return true;
        }

        // 新增遍历函数
        void Traverse()
        {
            for (auto& data : _table) {
                if (data._state == FULL) {
                    cout << data._kv.first<<"  "<< data._kv.second << endl;
                }
            }
        }
    private:
        vector<Data> _table;
        size_t _number;
    };
    void TestHT1()
    {
        hashTable<int, int> ht;
        int a[] = { 11,21,4,14,24,15,9 };
        for (auto e : a)
        {
            ht.insert({ e,e });
        }

        ht.insert({ 19,19 });
        ht.insert({ 19,190 });
        ht.insert({ 19,1900 });
        ht.insert({ 39,1900 });
        ht.Traverse();
        
    }
    void TestHT2()
    {
        hashTable<string, string> ht;
        ht.insert({ "sort", "排序" });
        ht.insert({ "left", "左边" });
        ht.Traverse();
    }
}

开散列

//开散列
namespace hash_openess
{

    //悬挂的节点
    template<class K, class V>
    struct HashNode
    {
        pair<K, V> _kv;
        HashNode<K, V>* _next;

        HashNode(const pair<K, V>& kv)
            :_kv(kv)
            , _next(nullptr)
        {}
    };

    template<class K, class V, class hash = Hash_to_int<K>>
    class HashTable
    {
        typedef HashNode<K, V> Node;
    public:
        HashTable()
            :_number(0)
        {
            _tables.resize(10, nullptr);
        }

        //插入
        bool insert(const pair<K, V>& kv)
        {
            hash to_int;
            size_t numi = to_int(kv.first) % _tables.size();

            //负载因子为1时进行扩容
            //即size与数据点相等
            if (_number == _tables.size())
            {
                vector<Node*> newTable(_tables.size()*2);
                //挪动数据
                for (size_t i = 0; i < _tables.size(); i++)
                {
                    Node* current = _tables[i];
                    while (current)
                    {
                        Node* next = current->_next;
                        size_t numii = to_int(current->_kv.first) % newTable.size();
                        
                        // 头插到新表
                        current->_next = newTable[numii];
                        newTable[numii] = current;
                        current = next;
                    }

                    _tables[i] = nullptr;
                }
                _tables.swap(newTable);
            }

            //进行头插
            Node* cmp = new Node(kv);
            cmp->_next = _tables[numi];
            _tables[numi] = cmp;
            _number++;
            return true;
        }

        //删除
        bool Erase(const K& key)
        {
            hash to_int;
            //找出位置
            size_t numi = to_int(key) % _tables.size();
            Node* prev = nullptr;
            Node* cur = _tables[numi];
            while (cur)
            {
                if (cur->_kv.first == key)
                {
                    if (prev == nullptr)
                    {
                        _tables[numi] = cur->_next;
                    }
                    else
                    {
                        prev->_next = cur->_next;
                    }
                    delete cur;
                    _number--;
                    return true;
                }
                prev = cur;
                cur = cur->_next;
            }
            return false;
        }

        //查找
        Node* Find(const K& key)
        {
            hash to_int;

            //找出位置
            size_t numi = to_int(key) % _tables.size();
            Node* cur = _tables[numi];
            while (cur)
            {
                if (cur->_kv.first == key)
                {
                    return cur;
                }
                cur = cur->_next;
            }
            return nullptr;
        }
        // 新增遍历函数
        void Traverse()
        {
            for (size_t i = 0; i < _tables.size(); i++)
            {
                Node* current = _tables[i];
                while (current)
                {
                    cout << current->_kv.first << "  " << current->_kv.second << endl;
                    current = current->_next;
                }
            }
        }
    private:
        vector<Node*> _tables;
        size_t _number;
    };

    void TestHT1()
    {
        HashTable<int, int> ht;
        int a[] = { 11,21,4,14,24,15,9 };
        for (auto e : a)
        {
            ht.insert({ e,e });
        }

        ht.insert({ 19,19 });
        ht.insert({ 19,190 });
        ht.insert({ 19,1900 });
        ht.insert({ 39,1900 });
        ht.Traverse();
        cout << ht.Find(19) << endl;
        ht.Erase(19);
        
        ht.Traverse();

    }
    void TestHT2()
    {
        HashTable<string, string> ht;
        ht.insert({ "sort", "排序" });
        ht.insert({ "left", "左边" });
        ht.Traverse();
    }


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值