散列函数与层级结构数据

来源:互联网 发布:linux vim 强制保存 编辑:程序博客网 时间:2024/05/22 12:23

近两天在温习数据结构时,对散列函数与树结构数据处理优化有些想法。

首先看看散列函数的定义:在数据元素的关键字与该元素的存储位置之间建立一种对应关系,将这种关系称为散列函数(hash function)

例如,哈希表(Hash table,也叫散列表),就是采用散列函数将元素数据映射成数据或链表的存储位置实现的,HashMap类似,只是映射结果是key不是位置。

期待c++标准库直接支持hashtable/hashmap/hashset的容器。

1、深化树层级

场景设想,目前我们有组对象,他们都有一个唯一的编号,一个很大的编号,为了快速访问和定位,很容易设想std::map<long long key, T val>去装载他们。

但很显然易见的是当map大到一定程度时对效率影响还是挺大的,这是就需要层级结构处置他们,就可以结合散列函数做一个类似的map装载他们:

给出的示例代码:

template <class T>
class OBJMAP
{
public:
    OBJMAP(){};
    ~OBJMAP(){};
    void insert(long long key,T val)
    {
        data[hash(key)][key]=val;
    };
    T getVal(long long key)
    {
        std::map<long long,std::map<long long,T> >::iterator it =  data.find(hash(key));
        if(it !=  data.end()){
            std::map<long long,T>::iterator it_obj = it->second.find(key);
            if(it_obj != it->second.end())
            {
                return it_obj->second;
            }
        }
        return T();
    };
    long long size()
    {
        long long ret = 0;
        std::map<long long,std::map<long long,T> >::iterator it = data.begin();
        while(it !=  data.end()){
            ret += static_cast<long>(it->second.size());
            it++;
        }
        return ret;        
    };
    //其他函数类似
private:
    long long hash(long long key)
    {
        //简单的散列表示,实际按需调整设定散列算法,例如前几位表示区域,中间几位表述类型,后面表示对象号等等
        return static_cast<int>(key/PAGECOUNT);
    };
private:
    //
    static const long long PAGECOUNT = 10000;
    std::map<long long,std::map<long long,T> > data;
};

2、扁平化树层级

场景设想,有时候我们会遇到这样一种情况,我们要识别一个对象,首先需要找到他所在区域,再找到所在类型,再更具编号识别到对象,看起来应该是这样存储的:

std::map<int,std::map<int,std::map<int,T> > >,如果数据量不大,这种多层级的如果通过散列函数概念,建立区域、类型、编号到位置key一对一的映射关系[1],或者说区域、类型、编号组合成一个key 对象[2],就能将多层级简化

[2]示列代码:

class KeyObj
{
public:
    KeyObj(int _domain,int _type, int _id)
        : m_domain(_domain),m_type(_type),m_id(_id)
    {    
    };
    //
    static int cmp_Key(const KeyObj &obj1, const KeyObj &obj2)
    {
        int diff = obj1.m_domain - obj2.m_domain;
        if(diff!=0)         return diff;
        diff = obj1.m_type - obj2.m_type;
        if(diff!=0)         return diff;
        diff = obj1.m_id - obj2.m_id;
        if(diff!=0)         return diff;
        return 0;    
    };
    int    m_domain;    
    int    m_type;        
    int    m_id;        
};
inline bool operator==(const KeyObj& obj1, const KeyObj& obj2) { return KeyObj::cmp_Key(obj1,obj2)==0 ; }
inline bool operator!=(const KeyObj& obj1, const KeyObj& obj2) { return KeyObj::cmp_Key(obj1,obj2)!=0 ; }
inline bool operator>=(const KeyObj& obj1, const KeyObj& obj2) { return KeyObj::cmp_Key(obj1,obj2)>=0 ; }
inline bool operator<=(const KeyObj& obj1, const KeyObj& obj2) { return KeyObj::cmp_Key(obj1,obj2)<=0 ; }
inline bool operator>(const KeyObj& obj1, const KeyObj& obj2)  { return KeyObj::cmp_Key(obj1,obj2)>0 ; }
inline bool operator<(const KeyObj& obj1, const KeyObj& obj2)  { return KeyObj::cmp_Key(obj1,obj2)<0 ; }

template <class T>
class MyObj
{
    MyObj(){};
    void insert(KeyObj key,T val)
    {
        data[key]=val;
    };
    void insert(int _domain,int _type, int _id,T val)
    {
        insert(KeyObj(_domain,_type,_id),val);
    };
    T getVal(KeyObj key)
    {
        std::map<KeyObj,T>::iterator it =  data.find(key);
        if(it !=  data.end()){
            return it->second;
        }
        return T();
    };
    //其他函数类似实现
private:
    std::map<KeyObj,T> data;//由于采用map,需要KeyObj实现map的key排序准则
};


散列表在实际应用场景要比这复杂很多,主要看其引入是否能降低访问复杂度、插入复杂度等,否则宁可不用。


0 0