【散列表】:散列

目录

一、桶和起始桶

二、散列函数

三、冲突解决

四、动态扩容

五、代码实现


散列表又称哈希表,查找只需要花费常数时间,查找效率极高,对庞大数据的查找很有作用。

散列的基本思想:理想的散列表数据结构只不过是一个包含一些项的具有固定大小的数组。(表的大小一般为素数)设该数组的大小为TbaleSize,我们向该散列表中插入数据,首先我们将该数据用一个函数(散列函数)映射一个数值x(位于0到TbaleSize1-1之间);然后将该数据插入到散列表的第x的单元。(如果有多个数据映射到同一个数值,这个时候就会发生冲突)

一、桶和起始桶

散列(哈希): 用一个散列函数把字典的数对映射到散列表的具体位置

散列的每一个位置

起始桶 关键字为k的数对在散列中的位置f(k)

二、散列函数

散列函数将要检索的项与索引(散列,散列值)关联起来,生成一种便于搜索的数据结构(散列表)。散列函数的构造准则:

hash函数的构造准则:简单、均匀。

(1)散列函数的计算简单,快速;

(2)散列函数能将关键字集合K均匀地分布在地址集{0,1,…,m-1}上,使冲突最小。

散列函数的构造方法有很多,具体不在这里详解,请看参考链接。

参考链接:散列函数(哈希)

1、除法散列函数

本文使用的是除法散列函数,这里做一下简单的介绍。

形式:f(k)=k%D

(k为关键字,D为散列的长度(桶的数量))

注意:

  • 理想的D是一个素数,当你不能找到接近散列长度的素数时,应该旋转2和19 之间的D
  • 选择除数D为奇,可以使关键字依赖所有位
  • 当D既是素数又不能被小于20的数整除,就能得到好的散列

三、冲突解决

冲突: 当两个关键字对应的起始桶相同

溢出: 如果存储桶没有足够的空间存储新的数对

哈希冲突解决方法主要由下图所示的一些方法,具体详情请看上面的链接。

四、动态扩容

扩容必须同时满足两个条件:

  • 存放新值的时候当前已有元素的个数达到阈值;
  • 存放新值的时候发生哈希冲突(当前key的hash值计算出来的数组下标位置已存在值)

扩容方法:

新建一个数组,容量为原来的2倍,遍历原来table中每个位置的链表,并对每个元素进行重新hash,得到在新数组的位置后插入。最后重新计算阈值。

五、代码实现

#include <iostream>
#include <string>
#include <vector>
#include <memory>

#include "list.h"

using namespace std;

/*******************************************
*                哈希表的数组实现              *
/*******************************************/
template <class K,class E>
class ArrayHash
{
public:
    ArrayHash(int divisions);
    ~ArrayHash();

    //判断是否为空
    bool empty(){return size_==0;}
    //获取哈希表存储数据的大小
    size_t size(){return size_;}

    //插入数对
    void insert(const pair<K,E> &thePair);

    //删除数对
    void erase(const K &key);

    //修改关键字key的键值
    void set(const K &key,const E &value);

    //根据关键字key搜索哈希表中的位置
    int search(const K &key)const;
    //更具关键字key查找数对
    pair<K,E> *find(const K &key)const;

    //打印哈希表
    void print();

private:
    pair<K,E> **table_; //哈希表
    hash<K> hash_;      //将类型K映射为整数
    size_t size_;       //哈希表中的数对个数
    int bucket_size_;   //哈希函数的除数
};

template <class K,class E>
ArrayHash<K,E>::ArrayHash(int bucket_size):bucket_size_(bucket_size)
{
    size_=0;
    //初始化哈希表
    table_=new pair<K,E>*[bucket_size_];
    for(int i=0;i<bucket_size_;++i){
        table_[i]=NULL;
    }
}

template <class K,class E>
ArrayHash<K,E>::~ArrayHash()
{
    for(int i=0;i<bucket_size_;++i){
        if(table_[i]!=NULL){
            delete table_[i];
        }
    }

    delete[] table_;
}

template <class K,class E>
void ArrayHash<K,E>::insert(const pair<K, E> &thePair)
{
    size_t index=search(thePair.first);

    if(table_[index]==NULL){
        table_[index]=new pair<K,E>(thePair);
        ++size_;
    }else if(table_[index]->first==thePair.first){
        table_[index]->second=thePair.second;
    }else{
        cerr<<"array hush is full!"<<endl;
        exit(0);
    }
}

template <class K,class E>
void ArrayHash<K,E>::erase(const K &key)
{
    size_t src_index=hash_(key)%bucket_size_;
    int index=search(key);

    if(table_[index]==NULL || table_[index]->first!=key){
        return ;
    }else{
        delete table_[index];
        table_[index]=NULL;
        --size_;
    }
}

template <class K,class E>
void ArrayHash<K,E>::set(const K &key, const E &value)
{
    size_t index=search(key);

    if(table_[index]==NULL){
        insert(make_pair(key,value));
    }else if(table_[index]->first==key){
        table_[index]->second=value;
    } else{
        cerr<<"array hush don't has this pair..."<<endl;
        exit(0);
    }
}

template <class K,class E>
int ArrayHash<K,E>::search(const K &key) const
{
    size_t index=hash_(key)%bucket_size_;

    int j=index;
    do{
        if(table_[j]==NULL || table_[j]->first==key){
            return j;
        }
        j=(j+1)%bucket_size_;
    }while(j!=index);

    return j;
}

template <class K,class E>
pair<K,E> *ArrayHash<K,E>::find(const K &key) const
{
    size_t index=search(key);

    if(table_[index]==NULL || table_[index]->first!=key){
        return NULL;
    }else{
        return table_[index];
    }
}

template <class K,class E>
void ArrayHash<K,E>::print()
{
    for(int i=0;i<bucket_size_;++i){
        cout<<i<<":";
        if(table_[i]!=NULL){
            cout<<table_[i]->first<<"->"<<table_[i]->second;
        }
        cout<<endl;
    }
}

/*******************************************
*                哈希表的链表实现              *
/*******************************************/
template <class K,class E>
class ListHash
{
public:
    ListHash(size_t bucket_size);
    ~ListHash(){}

    //判断是否为空
    bool empty(){return size_==0;}
    //获取哈希表存储数据的大小
    size_t size(){return size_;}

    //插入数对
    void insert(const pair<K,E> &thePair);

    //删除数对
    void erase(const K &key);

    //修改关键字key的键值
    void set(const K &key,const E &value);

    //根据关键字key搜索哈希表中的位置
    int search(const K &key)const;
    //更具关键字key查找数对
    pair<K,E> *find(const K &key)const;
    
    //打印哈希表
    void print();
private:
    typedef SingleList<pair<K,E>> List;
    shared_ptr<List> ptr_;
    size_t bucket_size_;
    size_t size_;
    hash<K> hash_;
};

template <class K,class E>
ListHash<K,E>::ListHash(size_t bucket_size):bucket_size_(bucket_size), size_(0)
{
    ptr_=shared_ptr<List>(new List[bucket_size_](),
                          [](List *p){delete[] p;});
}

template <class K,class E>
void ListHash<K,E>::insert(const pair<K, E> &thePair)
{
    size_t index=hash_(thePair.first)%bucket_size_;

    List *slist=ptr_.get()+index;

    for(int i=0;i<slist->size();++i){
        if(slist->get(i).first==thePair.first){
            slist->set(i,thePair);
            return;
        }
    }
    slist->insert(0,thePair);
    ++size_;
}

template <class K,class E>
void ListHash<K,E>::erase(const K &key)
{
    size_t index=search(key);
    List *slist=ptr_.get()+index;
    for(int i=0;i<slist->size();++i){
        if(slist->get(i).first==key){
            slist->erase(i);
            return ;
        }
    }

    cerr<<"Don't find key = "<<key<<" pair..."<<endl;
    return ;
}

template <class K,class E>
void ListHash<K,E>::set(const K &key,const E &value)
{
    pair<K,E> tmp(key,value);
    size_t index=hash_(key)%bucket_size_;
    List *slist=ptr_.get()+index;
    for(int i=0;i<slist->size();++i){
        if(slist->get(i).first==key){
            slist->set(i,tmp);
            return ;
        }
    }

    cerr<<"Don't find key = "<<key<<" pair,failed to change key values of pairs !!!"<<endl;
}

template <class K,class E>
int ListHash<K,E>::search(const K &key) const
{
    size_t index=hash_(key)%bucket_size_;
    List *slist=ptr_.get()+index;
    for(int i=0;i<slist->size();++i){
        if(key==slist->get(i).first){
            return index;
        }
    }

    return -1;
}

template <class K,class E>
pair<K,E> *ListHash<K,E>::find(const K &key) const
{
    size_t index=hash_(key)%bucket_size_;
    List *slist=ptr_.get()+index;
    for(int i=0;i<slist->size();++i){
        if(key==slist->get(i).first){
            return &slist->get(i);
        }
    }

    return NULL;
}

template <class K,class E>
void ListHash<K,E>::print() 
{
    for(int i=0;i<bucket_size_;++i){
        List *cur=ptr_.get()+i;
        if(cur->size()==0){
            continue;
        }
        cout<<i<<":";
        for(int j=0;j<cur->size();++j){
            pair<K,E> &tmp=cur->get(j);
            cout<<tmp.first<<"->"<<tmp.second<<",";
        }
        cout<<endl;
    }
}
#include "hashing.h"


int main()
{
    cout<<"=========>ArrayHash:"<<endl;
    ArrayHash<string,int> ahash(5);
    ahash.insert(make_pair("jin",100));
    ahash.insert(make_pair("qiu",200));
    ahash.insert(make_pair("kin",300));
    ahash.insert(make_pair("ol",400));
    ahash.print();
    cout<<"size:"<<ahash.size()<<endl;
    cout<<"========"<<endl;
    ahash.erase("kin");
    ahash.print();
    ahash.set("jin",250);
    ahash.print();
    cout<<"========"<<endl;
    pair<string,int> *l2=ahash.find("ol");
    if(l2!=NULL){
        cout<<"pair:"<<l2->first<<"->"<<l2->second<<endl;
    }else{
        cout<<"don't find"<<endl;
    };

    cout<<"qiu index:"<<ahash.search("qiu")<<endl;

    cout<<"=========>ListHash:"<<endl;
    ListHash<string,int> lhash(5);
    lhash.insert(make_pair("jin",100));
    lhash.insert(make_pair("qiu",200));
    lhash.insert(make_pair("kin",300));
    lhash.insert(make_pair("ol",400));
//    lhash.insert(make_pair("zhi",500));
//    lhash.insert(make_pair("wang",600));

    lhash.print();
    cout<<"size:"<<lhash.size()<<endl;
    cout<<"========"<<endl;
    lhash.erase("ol");
    lhash.print();
    cout<<"========"<<endl;
    lhash.set("jin",250);
    lhash.print();
    cout<<"========"<<endl;
    pair<string,int> *l1=lhash.find("jin");
    cout<<"pair:"<<l1->first<<"->"<<l1->second<<endl;
    cout<<"qiu index:"<<lhash.search("qiu")<<endl;

    return 0;
}

输出结果:

参考链接:

数据结构与算法——散列表类的C++实现(探测散列表)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值