这里浅谈一下Hashtable,Hashmap,map
1.首先说一下Hashtable
哈希表(Hash Table)也叫散列表,是根据关键码值直接访问
就是一个把关键码映射到表中的一个位置来访问记录的过程
这个映射函数叫做哈希函数,用hash()表示,存放记录的数组叫做哈希表(一个数组)
哈希表是一种高效的数据结构,主要体现在数据的查找上,几乎可以看成常数时间
为了解决hasntable冲突的问题,我这里列举出了两种方法来实现,开放式地址法和链式地址法
开放式地址发,以下是我定义的hashtable采用开发式地址法定义的数据结构,Hashtable的每一元素是Elemtype,为了解决冲突采用的hash算法是return ((key%M)+Irc(i))%M,如果hash后映射到有数据存在则采用增量的方式重新哈希
#define M 13
#define Nul -1
#define KeyType int
typedef struct{}Record; //记录级指针
typedef struct Elemtype
{
KeyType key;
Record *record;
}Elemtype;
typedef Elemtype HashArray[M];
typedef struct HashTable
{
HashArray Table;
int cursize;
}HashTable;
下面贴出完整的代码
#include
using namespace std;
#define M 13
#define Nul -1
#define KeyType int
typedef struct{}Record;
typedef struct Elemtype
{
KeyType key;
Record *record;
}Elemtype;
typedef Elemtype HashArray[M];
typedef struct HashTable
{
HashArray Table;
int cursize;
}HashTable;
void Init(HashTable *table)
{
table->cursize = 0;
for(int i = 0; i < M; ++i)
{
table->Table[i].key = Nul;
table->Table[i].record = NULL;
}
}
int Irc(int i)
{
return i;
}
int Hash(KeyType key,int i )
{
return ((key%M)+Irc(i))%M;//增量,解决冲突,当有冲突的时候往后移动
}
int Search(HashTable *table,KeyType key)
{
for(int i = 0; i < M; ++i)
{
int pos = Hash(key,i);
if(table->Table[pos].key == Nul)
{
return pos;
}
if(table->Table[pos].key == key)
{
return -1;
}
}
return -1;
}
bool Insert(HashTable *table,Elemtype val)
{
bool res = false;
int pos = Search(table,val.key);
if(pos != -1)
{
table->Table[pos] = val;
table->cursize += 1;
res = true;
}
return res;
}
以上是采用开发式地址的方法来解决hash冲突。
下面说说第二种方法,采用链式地址的方法来解决hash冲突
EG:如果key1和Key2映射到同一个结点上,则采用链表的形式连起来,如下图所示
一下是我定义的数据结构
#define M 13
#define NUL -1
#define Keytype int
typedef struct{}Record;
typedef struct ElemType
{
Keytype key;
Record *record;
}ElemType;
typedef struct HashNode
{
ElemType elem;
HashNode *next;
}HashNode;
typedef HashNode* HashArray[M];
typedef struct HashTable
{
HashArray Table;
int cursize;
}HashTable;
也就是说在Hashtable中每一个元素的类型其实是一个结点类型,带头节点的链表,采用此方法来解决链式地址冲突,下面贴出完整的代码
#include
using namespace std;
#define M 13
#define NUL -1
#define Keytype int
typedef struct{}Record;
typedef struct ElemType
{
Keytype key;
Record *record;
}ElemType;
typedef struct HashNode
{
ElemType elem;
HashNode *next;
}HashNode;
typedef HashNode* HashArray[M];
typedef struct HashTable
{
HashArray Table;
int cursize;
}HashTable;
HashNode* _BuyNode()
{
HashNode *p = new HashNode;
memset(p,0,sizeof(p));
return p;
}
void Init(HashTable *table)
{
table->cursize = 0;
for(int i = 0; i < M; ++i)
{
table->Table[i] = _BuyNode();
table->Table[i]->elem.key = -1;
table->Table[i]->next = NULL;
}
}
int Hash(Keytype key)
{
return key%M;
}
int Search(HashTable *table,Keytype key)
{
int pos = Hash(key);
HashNode *p = table->Table[pos];
while(p != NULL && p->elem.key != key)
{
p = p->next;
}
if(p == NULL)
{
return pos;
}
else
{
return -1;
}
}
bool Insert(HashTable *table,ElemType elem)
{
bool res = false;
int pos = Search(table,elem.key);
if(pos != -1)
{
HashNode *p = _BuyNode();
p->elem = elem;
p->next = table->Table[pos]->next;
table->Table[pos]->next = p;
res = true;
}
return res;
}
以上是采用链式地址发来解决冲突。
hashmap是建立在hashtable的基础之上的。两者之间没有太大的区别
采用vector作为数据,而数据里面的元素其实是一个list(链表),把key和value存储成一个pair对象实现了封装。hashtable和hashmap之间的区别如下
重要的不同是Hashtable的方法是同步的,而HashMap的方法不是。这就意味着,虽然你可以不用采取任何特殊的行为就可以在一个多线程的应用程序中用一个Hashtable,但你必须同样地为一个HashMap提供外同步。
只有HashMap可以让你将空值作为一个表的条目的key或value,而hashtable不允许
这里总结出了hashmap和hashtable的区别
3.下面说一下map
map的底层采用红黑树来实现,map的特点如下
1.祖先结点必须是黑色的
2.叶子结点是黑色的(NULL)结点
3.任意两个相同颜色的结点不能相邻
4.从根结点到叶子节点的所有路径所经过的节点都是相同的
这也是红黑树和VAL树的区别,红黑树和VAL树的时间复杂度都是O(logn),但是红黑并不追求完全平衡,而VAL树则要求左右子树的高度之差不超过1,追求完全平衡。
hashmap和map是有区别的,hashmap是基于hashtable来实现的,而map是由红黑树来实现的。
以上是我总结出来的几点,如果说的不对的地方,请大家指正,q^q,下一篇接着会讨论hash的扩容问题,和一致哈希算法的实现