散列表函数的实现

#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
//定义一个员工的类
class Employee{
    public:
        Employee(){name=""; salary=0.0; seniority=0;};// 初始构造函数
        Employee(const string & n, double sal, int sen):name(n), salary(sal), seniority(sen){}//赋值构造函数
        //获得该类的name成员
        const string & getName() const//返回一个string类型的引用
        { return name; }
 
        //重载==运算符   重载等号运算符  是为了下面查找键值的时候使用
        bool operator==(const Employee & rhs) const
        { return getName() == rhs.getName(); }
 
        //重载!=运算符 
        bool operator!=(const Employee & rhs) const
        { return !(*this == rhs); }
 //设计一个友元函数  用于输出信息
        friend ostream & operator<<(const ostream & os, const Employee & e){
            cout << "name: " << e.name << ",\tsalary: " << e.salary << ",\tseniority: " << e.seniority;
        }
    private:
        string name;//姓名
        double salary;//薪水
        int seniority;//级别
};
 
/****************************************************************
*   函数名称:hash(const HashedObj & key)
*   功能描述: 根据键值求个hash值,这个函数是根据一个特定的数学公式 
*   参数列表: key 数据项的键值 
*   返回结果:返回一个通过散列函数求得的值
*****************************************************************/
int hash(const string & key)
{
    int hashVal = 0;
 
    //用散列函数的那个公式求和
    for(int i = 0; i < key.length(); ++i)
        hashVal = 37*hashVal + key[i];
 
    return hashVal;//这是通过散列函数求得的值
}
 
/****************************************************************
*   函数名称:hash(const HashedObj & key)
*   功能描述: 根据Employee引用的键值求个hash值,这个函数是根据一个特定的数学公式 
*   参数列表: key 数据项的键值 
*   返回结果:返回一个通过散列函数求得的值
*****************************************************************/
int hash(const Employee & item)
{
    return hash(item.getName());
}
 
 
/****************************************************************
*   散列表类名称:HashTable
*   内容描述: 散列表类
*****************************************************************/
template<typename HashedObj>
class HashTable{
    public:
        explicit HashTable(int size = 11):array(nextPrime(size)), currentSize(0){makeEmpty();}//不能在隐式子转换中使用该函数
        ~HashTable();//析构函数
 
        bool containes(const HashedObj & x);//判断是否包含数据项x
        void makeEmpty();//清空散列表
        bool isEmpty();//判断是否是空表
        bool insert(const HashedObj & x);//插入项x
        bool remove(const HashedObj & x);//删除项x
 
        void print();//输出散列表中的内容
        int findPos(const HashedObj & x);//根据名字查找数据项
        HashedObj findElement(const HashedObj & x);//根据名字查找数据项,并返回
 //表明位置的状态信息
        enum EntryType {ACTIVE, EMPTY, DELETED};//每个数据单元都有一个info变量,表明该位置是否被占用、空或已删除
        
    private:
        //散列表的数据单元结构
        struct HashEntry{
            HashedObj element;//该散列表存放的数据
            EntryType info;//表明该位置的状态 对应与82行
            //结构的构造函数
            HashEntry(const HashedObj & e = HashedObj(), EntryType i = EMPTY):element(e), info(i){}
        };
 
        vector<HashEntry> array;//散列表  这是一个array数组
        int currentSize;//散列表中当前存放的元素个数
    private:
        void rehash();//再散列
        int myhash(const HashedObj & x) const;//散列函数
        int nextPrime(int n);//求的距离N最近的一个大于N的素数
        int prePrime(int n);//求距离N最近的一个小于N的素数
        bool isActive(int currentPos) const;//判断位置currentPos处的是否有元素
 
    public:
	//输出函数  输出这个点的信息
        friend ostream & operator<<(const ostream & os, const HashEntry & e){
            cout << "element: " << e.element << ", info = " << e.info;
        }
};
 
 
/****************************************************************
*   函数名称:findElement(const HashedObj & x) const
*   功能描述: 查找x的位置
*   参数列表: x是要查找的元素
*   返回结果:如果找到则返回该元素的引用
*****************************************************************/
template<typename HashedObj>
HashedObj HashTable<HashedObj>::findElement(const HashedObj & x)
{
    int currentPos = findPos(x);//找到x插入的位置
 
    if(isActive(currentPos))//找了则返回  isActive()函数判断这个位置的状态 也就是判断这个位置是否有元素
        return array[currentPos].element;//返回array数组这个位置的元素值
    else{//没有找到,返回一个空值
        HashedObj obj;
        return obj;
    }
}
 
 
/****************************************************************
*   函数名称:findPos(const HashedObj & x) const
*   功能描述: 查找x应该插入的位置
*   参数列表: x是要插入的元素
*   返回结果:如果找到空的位置则返回要插入的位置标号
*****************************************************************/
template<typename HashedObj>
int HashTable<HashedObj>::findPos(const HashedObj & x)
{
    //线性探测f(i) = i; f(i) = f(i-1) + 1;相隔为1
    //平方探测f(i) = i*i; f(i) = f(i-1) + 2*i - 1; 相隔为2*i-1
    //双散列,f(i) = i*hash2(x); f(i) = f(i-1)+hash2(x);相隔为hash2(x);
    //hash2(x) = R-(x%R); R=prePrime(array.size()),R为小于TableSize()的素数
    int offset = 1;
 
    int currentPos = myhash(x);
 
    //如果找到了空的位置则返回位置标号
    //如果找到了该元素x,则返回该元素的位置标号   找到这个位置前提的有元素  还要判断是否是要查找的元素
    while(array[currentPos].info != EMPTY && array[currentPos].element != x){
         //currentPos += offset;//线性探测
         currentPos += 2 * offset -1;//平方探测
         //currentPos += prePrime(array.size()) - myhash(x)%prePrime(array.size());//双散列
         offset++;
 
        if(currentPos >= array.size())
            currentPos -= array.size();
    }
    
    return currentPos;  //返回这个位置
}
 
 
/****************************************************************
*   函数名称:print()
*   功能描述: 输出散列表中的内容
*   参数列表: 无 
*   返回结果:无
*****************************************************************/
template<typename HashedObj>
void HashTable<HashedObj>::print()
{
	//<<已经被重载过了
    cout << "输出散列表中的内容: " << endl;
    for(unsigned i = 0; i < array.size(); ++i){
        if(isActive(i))//如果这个位置有元素 就输出
            cout << i << ": " << endl << array[i] << endl;
    }
}
 
/****************************************************************
*   函数名称:isEmpty()
*   功能描述: 判断散列表是否为空
*   参数列表: 无 
*   返回结果:无
*****************************************************************/
template<typename HashedObj>
bool HashTable<HashedObj>::isEmpty()
{
    return currentSize == 0;//是判断当前散列表的个数 根据散列表中元素的个数来判断这个表是否是空表
}
 
/****************************************************************
*   函数名称:makeEmpty()
*   功能描述: 清空散列表 
*   参数列表: 无 
*   返回结果:无
*****************************************************************/
template<typename HashedObj>
void HashTable<HashedObj>::makeEmpty()
{
    for(int i = 0; i < array.size(); ++i)
        array[i].info = EMPTY;//把信息定义为空
 
    currentSize = 0;//当前元素个数设为0
}
 
/****************************************************************
*   函数名称:containes(const HashedObj & x) const
*   功能描述: 判断散列表是否包含值为x的元素 
*   参数列表: x数据项
*   返回结果:如果包括x则返回true,否则返回false
*****************************************************************/
template<typename HashedObj>
bool HashTable<HashedObj>::containes(const HashedObj & x)
{
    //findPos(x)返回的位置是ACTIVE的说明存在该元素x
    return isActive(findPos(x));//判断位置x是否有元素
}
 
/****************************************************************
*   函数名称:isActive(int currentPos) const
*   功能描述: 判断位置currentPos处的是否有元素 
*   参数列表: currentPos是散列表currentPos处的位置 
*   返回结果:如果currentPos处有元素则返回true,否则返回false
*****************************************************************/
template<typename HashedObj>
bool HashTable<HashedObj>::isActive(int currentPos) const
{
    return array[currentPos].info == ACTIVE;//也就是查看这个点的状态  也就是比对状态信息是否是active
}
 
/****************************************************************
*   函数名称:remove(const HashedObj & x)
*   功能描述: 删除散列表中的值为x的元素 
*   参数列表: x数据项
*   返回结果:成功删除返回true,否则返回false
*****************************************************************/
template<typename HashedObj>
bool HashTable<HashedObj>::remove(const HashedObj & x)
{
    int currentPos = findPos(x);//查找x的位置 如果这点不存在  直接返回false
    if(!isActive(currentPos))
        return false;
 
    array[currentPos].info = DELETED;//懒惰删除,仅仅将标识位info设置为Deleted
 
    --currentSize;//元素个数减去1
    return true;
}
 
/****************************************************************
*   函数名称:insert(const HashedObj & x)
*   功能描述: 在散列表中插入元素x,如果插入项已经存在,则什么都不做。
*             否则将其放在表的前端
*   参数列表: x数据项
*   返回结果:插入成功返回true, 否则返回false
*****************************************************************/
template<typename HashedObj>
bool HashTable<HashedObj>::insert(const HashedObj & x)
{
    int currentPos = findPos(x);//先找到位置
    if(isActive(currentPos))//如果该位置处已经存放了该元素,就是这里有与插入的值相等的元素,则之间返回false
        return false;
 
    array[currentPos] = HashEntry(x, ACTIVE);//把这个数据单元放到散列表中去
 
    //如果当前散列表中元素的个数大于散列表长度的一半,则扩大散列表为原来的2倍
//散列表扩容
    if(++currentSize > array.size()/2)
        rehash();//扩充表的大小
 
    return true;
 
}
 
 
/****************************************************************
*   函数名称:~HashTable()
*   功能描述: 析构函数
*   参数列表: 无
*   返回结果:无
*****************************************************************/
template<typename HashedObj>
HashTable<HashedObj>::~HashTable()
{
    
}
 
 
/****************************************************************
*   函数名称:prePrime(int n)
*   功能描述: 获得距离n最近的一个小于n的素数 
*   参数列表: n表示数值 
*   返回结果:返回一个素数 
*****************************************************************/
template<typename HashedObj>
int HashTable<HashedObj>::prePrime(int n)
{
    int i;
 
    if(n % 2 == 0)
        n--;
 
    for(; ; n -= 2){
        for(i = 3; i*i <= n; i += 2){//i是从3开始 对其取余数 然后判断是否是素数 如果是则返回
            if(n % i == 0)
                goto ContOuter;//这个的作用就是跳出这个循环
        }
        return n;
 
        ContOuter: ;
    }
}
 
/****************************************************************
*   函数名称:nextPrime(int n)
*   功能描述: 获得距离n最近的一个大于n的素数 
*   参数列表: n表示数值 
*   返回结果:返回一个素数 
*****************************************************************/
template<typename HashedObj>
int HashTable<HashedObj>::nextPrime(int n)
{
    int i;
 
    if(n % 2 == 0)//要求得是素数 首先排除偶数这一选项
        n++;
 
    for(; ; n += 2){
        for(i = 3; i*i <= n; i += 2)
            if(n % i == 0)
                goto ContOuter;
        return n;
        ContOuter: ;
    }
}
/****************************************************************
*   函数名称:rehash()
*   功能描述: 扩大散列表的大小
*   参数列表: 无
*   返回结果:无 
*****************************************************************/
template<typename HashedObj>
void HashTable<HashedObj>::rehash()
{
    
    vector<HashEntry> oldArray = array;
 
    //创建一个新的大小为原来两倍大小的散列表
    array.resize(nextPrime(2 * oldArray.size()));
 //先将其初始化为空
    for(int i = 0; i < array.size(); ++i)
        array[i].info = EMPTY;
 
    currentSize = 0;
    //复制散列表  将原来散列表的信息复制过来
    for(int i = 0; i < oldArray.size(); ++i){
        if(oldArray[i].info == ACTIVE)
            insert(oldArray[i].element);
    }
}
 
/****************************************************************
*   函数名称:myhash(const HashedObj & key)
*   功能描述: 根据键值求个hash值 
*   参数列表: key 数据项的键值 
*   返回结果:返回hash值
*****************************************************************/
template<typename HashedObj>
int HashTable<HashedObj>::myhash(const HashedObj & key) const
{
    int hashVal = hash(key);
    
    hashVal %= array.size();//根据键值获得哈希值   取余数的的除数设置为这个数组的长度
 
    if(hashVal < 0)
        hashVal += array.size();
 
    return hashVal;
}
 
 
 
 
int main()
{//先初始化这些数据
    Employee e1("linux", 101.00, 1);
    Employee e2("ever", 102.00, 2);
    Employee e3("peter", 103.00, 3);
    Employee e4("may", 104.00, 4);
    Employee e5("usa", 105.00, 5);
    Employee e6("sal", 106.00, 6);
    Employee e7("usa", 107.00, 7);//和上面的值重复,所以这个值会被忽略
    Employee e8("jan", 108.00, 8);
    Employee e9("kro", 109.00, 9);
    Employee e10("bei", 110.00, 10);
    
    Employee e12("bbb", 110.00, 10);
 //再讲这些值放入到数组中去
    vector<Employee> v;
    v.push_back(e1);
    v.push_back(e2);
    v.push_back(e3);
    v.push_back(e4);
    v.push_back(e5);
    v.push_back(e6);
    v.push_back(e7);
    v.push_back(e8);
    v.push_back(e9);
    v.push_back(e10);
 
    cout << "v: " << endl;
	//先输出这个哈希散列表的值
    for(unsigned i = 0; i < v.size(); ++i)
        cout << v[i] << endl;
    cout << endl;
 
    HashTable<Employee> hashTable;
    
    for(unsigned i = 0; i < v.size(); ++i)
       //那个散列表数组中的元素都插入到哈希表中去
	 hashTable.insert(v[i]);
 //输出哈希表的信息
    hashTable.print();
 
    cout << endl;
 
    cout << "测试包含函数containes: " << endl; 
    if(hashTable.containes(e10))
        cout << "containe e10" << endl;
    else 
        cout << "not containe e10" << endl;
 
    if(hashTable.containes(e12))
        cout << "containe e12" << endl;
    else 
        cout << "not containe e12" << endl;
        
    cout << "\n测试findElement(): " << endl;
    
    Employee e11 = hashTable.findElement(e8);
    cout << "e11: " << e11 << endl;
    cout << endl;
 
    cout << "测试isEmpty(): " << endl;
    if(hashTable.isEmpty())
        cout << "hashTable is Empty " << endl;
    else
        cout << "hashTable is not Empty " << endl;
    cout << endl;
 
    cout << "测试makeEmpty(): " << endl;
    hashTable.makeEmpty();
    if(hashTable.isEmpty())
        cout << "hashTable is Empty " << endl << endl;
    else
        cout << "hashTable is not Empty " << endl;
 
    return 0;
}


下面是运行的结果

v: 
name: linux,	salary: 101,	seniority: 1
name: ever,	salary: 102,	seniority: 2
name: peter,	salary: 103,	seniority: 3
name: may,	salary: 104,	seniority: 4
name: usa,	salary: 105,	seniority: 5
name: sal,	salary: 106,	seniority: 6
name: usa,	salary: 107,	seniority: 7
name: jan,	salary: 108,	seniority: 8
name: kro,	salary: 109,	seniority: 9
name: bei,	salary: 110,	seniority: 10

输出散列表中的内容: 
1: 
element: name: kro,	salary: 109,	seniority: 9, info = 0
3: 
element: name: jan,	salary: 108,	seniority: 8, info = 0
4: 
element: name: may,	salary: 104,	seniority: 4, info = 0
5: 
element: name: bei,	salary: 110,	seniority: 10, info = 0
6: 
element: name: usa,	salary: 105,	seniority: 5, info = 0
17: 
element: name: ever,	salary: 102,	seniority: 2, info = 0
18: 
element: name: sal,	salary: 106,	seniority: 6, info = 0
21: 
element: name: peter,	salary: 103,	seniority: 3, info = 0
22: 
element: name: linux,	salary: 101,	seniority: 1, info = 0

测试包含函数containes: 
containe e10
not containe e12

测试findElement(): 
e11: name: jan,	salary: 108,	seniority: 8

测试isEmpty(): 
hashTable is not Empty 

测试makeEmpty(): 
hashTable is Empty 

添加链接描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值