散列表——分离链接法

散列表由一个二级指针构成,二级指针的每一个节点指向一个单链表。

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







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值