hashtable模板的简单实现(二)

hashtable模板的简单实现(二)

转载注明出处

知识标签:hashtable tamplate C++ 函数指针


本程序使用线性探测法

数学递推公式

Hi = ( H(key) + di ) % m
- Hi表示发生冲突时第i次探测的散列地址
- H(key)表示根据key值第一次获得的散列地址
- di为增量序列,本程序取di = 1, 3, 5, 7…
- m为散列表长

code

hashtable.h

#ifndef __HASHTABLE_H__
#define __HASHTABLE_H__

#include<iostream>
#include<vector>
#include<functional>

template<typename T>
class hashtable
{
    public:

        typedef size_t (*HS)(const T&);

        //构造函数,初始化函数指针变量,hash数组大小,hashtable当前元素个数
        hashtable(HS hs, size_t size = 100) : phash(hs), array(size), currentSize(0)
        {//array(size)调用hashElem的无参构造函数size次,而每个hashElem无参构造函数调用T的无参构造函数1次

            //为每个hashElem进行逻辑初始化
            for(size_t i = 0; i != array.size(); ++i)
                array[i].flag = EMPTY;
        }

        ~hashtable(){}

        //判断t是否在hashtable中
        bool isin(const T& t)
        {
            return array[getindex(t)].flag == ACTIVE;
        }

        //逻辑删除t
        bool remove(const T& t)
        {
            hashElem& he = array[getindex(t)];
            if(he.flag != ACTIVE)
                return false;
            else
            {
                he.flag = DELETED;
                --currentSize;
                return true;
            }
        }

        //插入t
        bool insert(const T& t)
        {
            hashElem& he = array[getindex(t)];
            //如果存在该元素,且该元素有效,插入失败
            if(he.flag == ACTIVE)
                return false;

            if(he.flag == DELETED)
            {//如果存在该元素,且该元素无效。把它置为有效,表示逻辑添加
                he.flag = ACTIVE;
            }
            else
            {//如果不存在该元素

                //1.调用hashElem的operator=  2.调用两参构造函数
                he = hashElem(t, ACTIVE);

                //保证负载因子 <= 0.5
                if(currentSize + 1 > array.size() / 2)
                    resize2();
            }
            ++currentSize;

            return true;
        }

        void show()
        {
            typename std::vector<hashElem>::iterator iter = array.begin();
            while(iter != array.end())
            {
                //下句代码可得:T一定要重载operator<<
                if((*iter).flag == ACTIVE)
                    std::cout << (*iter).element << std::endl;
                else
                    std::cout << "---" << std::endl;
                ++iter;
            }
        }

        //array元素内存空间的三种状态标记
        enum elemFlag {EMPTY, ACTIVE, DELETED};

        class hashElem
        {
            public:
                T element;
                elemFlag flag;
                hashElem(){}
                //调用T的拷贝构造函数
                hashElem(const T& em, elemFlag ef) : element(em), flag(ef){}
        };

    public:

        //hash函数指针
        HS phash;
        //hashtable数组
        std::vector<hashElem> array;
        //hashtable当前大小
        size_t currentSize;

    private:

        //返回值currentIndex的2种情况:1.存储过值,且等于x 2.没存储过值
        size_t getindex(const T& t)
        {//如果array[currentPos]中存储过值,但不等于t,就继续向下寻找

            size_t currentIndex = myhash(t);
            size_t offset = 1;
            //T一定要重载operator!=
            while(array[currentIndex].flag != EMPTY && array[currentIndex].element != t)
            {//如果array[currentPos]中存储过值,但不等于x,就继续向下寻找

                //Hi = ( H(T) + offseti ) % array.size()
                //其中offseti = 1, 3, 5, 7...
                currentIndex += offset;
                if(currentIndex >= array.size())
                {
                    currentIndex %= array.size();
                }
                offset += 2;
            }

            return currentIndex;
        }

        //hashtable以2倍大小自增长
        void resize2()
        {
            //备份
            std::vector<hashElem> oldarray = array;
            //扩容
            array.resize(2 * array.size());
            for(size_t i = 0; i != array.size(); ++i)
                array[i].flag = EMPTY;
            currentSize = 0;

            //转移数据到新hashtable
            for(size_t i = 0; i != oldarray.size(); ++i)
                if(oldarray[i].flag == ACTIVE)
                    insert(oldarray[i].element);
        }

        size_t myhash(const T& t)
        {//压缩映射
            return phash(t) % array.size();
        }
};

#endif

main.cpp

#include<iostream>
#include<string>
#include<functional>
#include "hashtable.h"

class node
{
    public:

        std::string name;
        size_t score;

    public:

        node(){}

        node(const std::string& str, size_t sc)
        {
            name = str;
            score = sc;
        }

        node(const node& nd)
        {
            name = nd.name;
            score = nd.score;
        }

        friend bool operator!=(const node& left, const node& right)
        {
            return left.name != right.name;
        }

        //operator=可省略,因为系统自动生成
        node& operator=(const node& other)
        {
            name = other.name;
            score = other.score;
            return *this;
        }

        friend std::ostream& operator<<(std::ostream& out, node& nd)
        {
            out << "( " << nd.name << ", " << nd.score << " )" << std::flush;
            return out;
        }
};

size_t myhash(const node& nd)
{
    return std::hash<std::string>()(nd.name);
}

int main(void)
{
    hashtable<node> ht(&myhash, 6);

    ht.insert(node("小明", 45));
    ht.insert(node("小花", 89));
    ht.insert(node("小红", 88));
    ht.insert(node("小王", 78));
    ht.insert(node("小黄", 99));
    ht.insert(node("小李", 76));
    ht.insert(node("小周", 65));
    ht.insert(node("小马", 98));
    ht.show();

    std::cout << "---------------------------" << std::endl;
    ht.remove(node("小马", 98));
    ht.remove(node("小红", 88));
    ht.show();

    if(ht.isin(node("小马", 98)))
        std::cout << "in" << std::endl;
    else
        std::cout << "not in" << std::endl;

    return 0;
}

结果

这里写图片描述
第二张
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值