散列表由一个二级指针构成,二级指针的每一个节点指向一个单链表。
向散列表中插入电影《云图》里的一句台词:“Yesterday my life was headed in one direction, today it is headed in another. Yesterday I believe that I could not do, today but I do.” 为了方便,插入的单词均为小写字母。
散列函数为单词首字母和字母a的差值:h(key) = key[0] - 'a', 散列表大小定义为26个。重复出现的单词只插入一次。
头文件定义如下,单链表节点char data[10]正好足够储存最长的单词"yesterday\0"。
禁止拷贝构造和赋值运算符。
hashFunc()函数和findKey()函数声明为私有,作为类内部使用,不向外提供接口。
#ifndef _HASHLIST_H_
#define _HASHLIST_H_
struct ListNode
{
char data[10];
ListNode* next;
};
class HashList
{
public:
HashList(int listsize);
~HashList();
private:
HashList(const HashList& h);
HashList& operator=(const HashList& h);
public:
void insertKey(const char* key);
void print();
private:
ListNode* findKey(const char* key);
int hashFunc(const char* key);
private:
int m_listsize;
ListNode** m_hashlist;
};
#endif // _HASHLIST_H_
hashlist.cpp定义如下。
构造函数完成数据成员的初始化。
析构函数先删除每个节点所指的单链表,再删除散列表。
findKey()函数返回key所在的链表节点的指针,没找到返回NULL。
insertKey()函数需要判断三种情况:
1.散列表节点所指的链表中已经储存有该单词,直接return;
2.散列表节点为空,指向新申请的链表节点;(此时不能使用p->next,会发生segmentation fault)
3.散列表节点不为空,接至所指链表的尾节点。
#include "hashlist.h"
#include <string.h>
#include <iostream>
HashList::HashList(int listsize)
:m_listsize(listsize)
{
m_hashlist = new ListNode*[listsize];
memset(m_hashlist, 0, listsize * sizeof(ListNode*));
}
HashList::~HashList()
{
for(int i = 0; i < m_listsize; i++)
{
while(m_hashlist[i] != NULL)
{
ListNode* t = m_hashlist[i];
m_hashlist[i] = m_hashlist[i]->next;
delete t;
}
}
delete[] m_hashlist;
}
int HashList::hashFunc(const char* key)
{
return key[0] - 'a';
}
ListNode* HashList::findKey(const char* key)
{
ListNode* p = m_hashlist[hashFunc(key)];
while(p != NULL && (strcmp(p->data, key) != 0))
{
p = p->next;
}
return p;
}
void HashList::insertKey(const char* key)
{
if(findKey(key) != NULL)
{
return;
}
ListNode* t = new ListNode;
memset(t, 0, sizeof(ListNode));
strcpy(t->data, key);
t->next = NULL;
int i = hashFunc(key);
if(m_hashlist[i] == NULL)
{
m_hashlist[i] = t;
}
else
{
ListNode* p = m_hashlist[i];
while(p->next != NULL)
{
p = p->next;
}
p->next = t;
}
}
void HashList::print()
{
for(int i = 0; i < m_listsize; i++)
{
std::cout << "hashlist " << i << " : ";
for(ListNode* p = m_hashlist[i]; p != NULL; p = p->next)
{
std::cout << p->data << "->";
}
std::cout << "NULL" << std::endl;
}
}
测试代码如下。
#include "hashlist.h"
int main()
{
const char *str[] = {"yesterday", "my", "life", "was", "headed", "in", "one", "direction", "today", "it",
"is", "headed", "in", "another", "yesterday", "i", "believe", "that", "i", "could",
"not", "do", "today", "but", "i", "do"};
HashList h(26);
for (unsigned int i = 0; i < sizeof(str)/sizeof(str[0]); i++)
{
h.insertKey(str[i]);
}
h.print();
return 0;
}
运行结果如下,valgrind检测无异常。