复习数据结构和算法04-Hash Table(线型寻址散列)

#ifndef _ROC_HASH_TABLE_H
#define _ROC_HASH_TABLE_H

#include <iostream>
#include <utility>


//Hash Table
//线形开址
template<typename KeyType, typename ValType>
class HashTable{
public:
 typedef std::pair<KeyType, ValType> KeyValUnion; //键-值对
 int    m_nTableSize;  //表大小
 KeyValUnion  *m_Table;   //表中存储的值
 int    *m_UsedTable;  //标记当前空间是否已使用
public:
 //功能: 构造函数,初始化Hash表中元素值
 HashTable():m_nTableSize(0), m_Table(NULL), m_UsedTable(NULL)
 {}

 //功能: 构造函数,生成一个大小为nSize的空哈希表
 //参数:
 // nSize: Hash表大小
 HashTable(int nSize):m_nTableSize(0), m_Table(NULL), m_UsedTable(NULL)
 {
  //创建哈希表
  CreateHashTable(nSize);
 }

 //功能:构造函数,用一个已存的Hash表初始化一个新表,表大小以及数据相同
 //参数:
 // hashTable: 已存Hash表
 HashTable(const HashTable<KeyType, ValType> &hashTable)
 {
  m_nTableSize = 0;
  m_Table = new KeyValUnion[hashTable.m_nTableSize];
  if(NULL == m_Table)
   return;
  
  m_UsedTable = new int[hashTable.m_nTableSize];
  if(NULL == m_UsedTable)
  {
   delete [] m_Table;
   m_Table = NULL;
   return;
  }
  
  m_nTableSize = hashTable.m_nTableSize;
  memcpy(m_Table, hashTable.m_Table, sizeof(KeyValUnion)*m_nTableSize);
  memcpy(m_UsedTable, hashTable.m_UsedTable, sizeof(int)*m_nTableSize);
 }

 //功能: 构造函数,用已存Hash表初始化一个大小为nSize的Hash表
 //参数:
 // nSize: Hash表大小;
 // hashTable: 已存Hash表,用于提供数据
 // lpfGetInt: 函数指针,用于将KeyType转为int值以计算在Hash表中的索引
 HashTable(int nSize, const HashTable<KeyType, ValType> &hashTable, int (*lpfGetInt)(const KeyType&))
 {
  CreateHashTable(nSize, hashTable, lpfGetInt);
 }

 //功能: 析构函数
 ~HashTable()
 {
  Destroy();
 }

 //功能: 销毁当前Hash表
 void Destroy()
 {
  m_nTableSize = 0;
  if(m_Table)
  {
   delete [] m_Table;
   m_Table = NULL;
  }

  if(m_UsedTable)
  {
   delete [] m_UsedTable;
   m_UsedTable = NULL;
  }
 }

 //功能: 创建大小为nSize的Hash表
 //参数:
 // nSize: Hash表大小
 //返回值: 若创建成功则返回0, 否则失败返回-1
 int CreateHashTable(int nSize)
 {
  if(nSize<1)
   return -1;

  KeyValUnion *valTable = new KeyValUnion[nSize];
  if(NULL == valTable)
   return -1;
  
  int *usedTable = new int[nSize];
  if(NULL == usedTable)
  {
   delete [] valTable;
   valTable = NULL;
   return -1;
  }
  
  //销毁Hash表中原有数据
  Destroy();

  m_Table  = valTable;
  m_UsedTable  = usedTable;
  m_nTableSize = nSize;
  memset(m_Table, 0, sizeof(KeyValUnion)*nSize);
  memset(m_UsedTable, 0, sizeof(int)*nSize);

  return 0;
 }

 //功能: 创建一个大小为nSize的Hash表,并的HashTable
 //参数:
 // nSize: Hash表大小;
 // hashTable: 已存Hash表,用于提供数据
 // lpfGetInt: 函数指针,用于将KeyType转为int值以计算在Hash表中的索引
 //返回值:若创建成功则返回0,否则返回-1
 int CreateHashTable(int nSize, const HashTable<KeyType, ValType> &hashTable, int (*lpfGetInt)(const KeyType&))
 {
  if(nSize<1)
   return -1;

  if(&hashTable == this)
   return -1;

  if(CreateHashTable(nSize)!=0)
   return -1;

  int result;
  for(int i=0; i<hashTable.m_nTableSize; i++)
  {
   //若hashTable的当前空间已存储数据,则插入到新Hash表中
   if(hashTable.m_UsedTable[i]!=0)
   {
    result = Insert(hashTable.m_Table[i].first, hashTable.m_Table[i].second, lpfGetInt);
    if(result != 0)
     return -1;  //当前表已满,插入失败,之前插入的元素已复制到当前表中
   }
  }

  return 0;
 }

 //功能: 查找键值为key的数据, 并获取该键值对应的数据
 //参数:
 // key: 用于查找数据的键值
 // outVal[out]: 输出值, 该键值对应的数据
 // lpfGetInt: 函数指针,用于将KeyType转为int值以计算在Hash表中的索引
 //返回值: 查找成功则返回0, 否则返回-1
 int Search(const KeyType &key, ValType &outVal, int(*lpfGetInt)(const KeyType&))
 {
  //计算索引值
  int idx = lpfGetInt(key)%m_nTableSize;
  
  //若当前空间未使用,查找失败
  if(0==m_UsedTable[idx])
   return -1;

  int curIdx = idx;
  do{
   //检查当前项键值是否正确
   if(m_Table[curIdx].first == key)  //用户需要为KeyType重载“==”运算符
   {
    outVal = m_Table[curIdx].second; //用户需要为ValType重载“=”运算符
    return 0;  //查找成功
   }
   ++curIdx;
   curIdx = curIdx % m_nTableSize;
  }while(m_UsedTable[curIdx]!=0 && curIdx != idx);
  
  return -1;  //查找失败
 }

 //功能:向Hash表插入数据
 //参数:
 // key: 用于计算索引的键值
 // val: 插入值, 该键值对应的数据
 // lpfGetInt: 函数指针,用于将KeyType转为int值以计算在Hash表中的索引
 //返回值: 插入数据成功则返回0, 否则返回-1
 int Insert(const KeyType &key, const ValType &val, int(*lpfGetInt)(const KeyType&))
 {
  //起始索引
  int idx = lpfGetInt(key)%m_nTableSize;

  //碰撞处理 线型寻址散列
  int curIdx = idx;
  do{
   //若线形开址找到空闲空间则插入元素
   if(0 == m_UsedTable[curIdx])
   {
    m_UsedTable[curIdx] = 1;   //标为已用
    m_Table[curIdx].first = key;  //用户需要为KeyType重载“=”运算符
    m_Table[curIdx].second = val;  //用户需要为ValType重载“=”运算符
    return 0;
   }
   curIdx = (curIdx+1)%m_nTableSize;
  }while(curIdx != idx);
  return -1;
 }
 
 //功能: 打印Hash表中元素
 void Print()
 {
  for(int i=0; i<m_nTableSize; i++)
   std::cout<<"Index: "<<i<<", Used: "<<(m_UsedTable[i]?"True":"False")<<", Key: "
      <<m_Table[i].first<<", Val: "<<m_Table[i].second<<std::endl;
 }
};

#endif //#ifndef _ROC_HASH_TABLE_H

 

//-----------------------------------------------------------------------------------------------------------
//test.Cpp
#include "stdafx.h"
#include "string.h"
#include "HashTable.h"


int GetInt(const double& val)
{
 return int(val+0.5);
}
struct ValType{
 char name[8];
 int id;
public:
 ValType& operator=(const ValType &val)
 {
  id = val.id;
  memcpy(name, val.name, sizeof(char)*8);
  return *this;
 }
 friend std::ostream& operator<<(std::ostream &out, const ValType &val);
};

std::ostream& operator<<(std::ostream &out, const ValType &val)
{
 out<<"ID = "<<val.id<<", Name = "<<val.name;
 return out;
}

int _tmain(int argc, _TCHAR* argv[])
{
 int result;
 HashTable<double, ValType> hashTable(11);
 ValType val;
 val.id = 1;
 strcpy(val.name, "a");
 result = hashTable.Insert(80.5, val, GetInt);  //1 a
 val.id++;
 val.name[0]++;
 result = hashTable.Insert(40.2, val, GetInt);  //2 b
 val.id++;
 val.name[0]++;
 result = hashTable.Insert(65.5, val, GetInt);  //3 c
 val.id++;
 val.name[0]++;
 result = hashTable.Insert(24.3, val, GetInt);  //4 d
 val.id++;
 val.name[0]++;
 result = hashTable.Insert(58.2, val, GetInt);  //5 e
 val.id++;
 val.name[0]++;
 result = hashTable.Insert(35.6, val, GetInt);  //6 f
 
 hashTable.Print();
 std::cout<<std::endl<<std::endl;
 ValType a6;
 result = hashTable.Search(35, a6, GetInt);
 result = hashTable.Search(58.2, a6, GetInt);
 HashTable<double, ValType> hashTable2;
 hashTable2.CreateHashTable(8, hashTable, GetInt);
 hashTable2.Print();
 return 0;
}

注意:
       1.该Hash Table处理碰撞时使用线型寻址散列。
       2.用户需要为KeyType重载“=”和“== ”运算符
       3.用户需要为ValType重载“=”运算符

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值