您的位置:首页 > 理论基础 > 数据结构算法

散列表——分离链接法

2017-05-05 13:24 323 查看
散列表由一个二级指针构成,二级指针的每一个节点指向一个单链表。

向散列表中插入电影《云图》里的一句台词:“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检测无异常。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  散列表 数据结构