散列(哈希表)

来源:互联网 发布:乌克兰危机 知乎 编辑:程序博客网 时间:2024/06/08 05:31

散列是一种用于以常数平均时间执行插入、删除和查找的技术。理想的散列表数据结构是一个包含有关键字的具有固定大小的数组。典型情况下,一个关键字就是一个带有相关值的字符串。


实现:通常把表的大小记作TableSize。每个关键字被映射到从0到TableSize-1这个范围中的某个数,并且被放到适当的单元中。这个映射就叫做散列函数。


散列函数:如果输入的关键字是整数,则一般方法是直接返回“Key mod TableSize”的结果,除非Key具有某些不理想的性质。例如,若表的大小是10而关键字都以0为个位,则此时上述标准的散列函数就是一个不好的选择。为了避免上面那种情况,通常保证表的大小是素数。

冲突:如果当一个元素被插入时另一个元素已经存在(散列值相同),那么就产生一个冲突,这个冲突需要消除。
解决冲突的方法有:分离连接法和开放定址法。


一、分离链接法
分离链接法是将散列到同一个值的所有元素保留到一个表中。
#include<iostream>
using namespace std;

typedef struct listNode {
        const char *value;
        struct listNode* next;
}ListNode;

typedef struct hashTable {
        int tableSize;
        ListNode **theLists;
}HashTable;

unsigned int Hush(const char* key,int tableSize);
HashTable* InitHashTable(int tableSize);
ListNode* Find(const char *key,HashTable *H);
void Insert(const char *key,HashTable *H);

unsigned int
Hush(const char *key,int tableSize)
{
         unsigned int hashVal = 0;
         while (*key != '\0')
                hashVal = (hashVal << 5) + *key++;
         return hashVal % tableSize;
}

HashTable* 
InitHashTable(int tableSize)
{
         int i;
         HashTable *H;
         H = (HashTable*)malloc(sizeof(struct hashTable));
         if (H == NULL)
                 printf("out of space for H!");

         H->theLists = (ListNode**)malloc(sizeof(struct listNode)*tableSize);
         if (H->theLists == NULL)
                 printf("out of space for H->theLists");

         for (i = 0; i < H->tableSize; i++) {
                 H->theLists[i] = (ListNode*)malloc(sizeof(struct listNode));
         if (H->theLists[i] == NULL)
                 printf("out of space");
         else
                 H->theLists[i]->next = NULL;
         }
         return H;
}

ListNode* 
Find(const char *key, HashTable *H)
{
         ListNode *p;
         ListNode *L;
         L = H->theLists[Hush(key,H->tableSize)];
         p = L->next;
         while (p != NULL && p->value != key)
                     p = p->next;
         return p;
}

void 
Insert(const char *key, HashTable *H)
{
        ListNode* p, *temp;
        ListNode *L;
        p = Find(key,H);
        if (p == NULL)
        {
                 temp = (ListNode*)malloc(sizeof(ListNode));
                 if (temp == NULL)
                          printf("out of space");
                 else {
                           L=H->theLists[Hush(key,H->tableSize)];
                           temp->next = L->next;
                           temp->value = key;
                           L->next = temp;
                         }
         }
}


二、开放定址--平方探测法


分离链接法的缺点是需要指针,由于需要给新单元分配地址需要时间,导致算法速度有些慢。开放定址散列法是一种不用链表解决冲突的方法。


#include<iostream>

using namespace std;

#define MINSIZE 100

static int MinTableSize = MINSIZE;
enum EntryKind {Legitimate,Empty,Deleted};

struct HashEntry
{
          char* value;
          enum EntryKind info;
};


typedef struct HashTb
{
         int TableSize;
         struct HashEntry *theCells;
}HashTable;

int NextPrime(int TableSize);
void handlError(char *msg);
unsigned int Hash(char *key,int TableSize);
HashTable* InitializeTable(int TableSize);
unsigned int Find(char*,HashTable *H);
void Insert(char*,HashTable *H);
HashTable* Rehash(HashTable *H);

unsigned int
Hash(char *key, int TableSize)
{
            unsigned int hashVal=0;
            while (*key != '\0')
            hashVal = (hashVal << 5) + *key++;
            return hashVal % TableSize;
}

HashTable*
InitializeTable(int TableSize)
{
        HashTable *H;
        int i;
        if (TableSize < MinTableSize)
        {
                handlError("Table size is too small");
        }

        H = (HashTable*)malloc(sizeof(HashTable));
        if (H == NULL)
                handlError("malloc for H is error");

         H->TableSize = NextPrime(TableSize);

         H->theCells = (struct HashEntry*)malloc(sizeof(struct HashEntry)*H->TableSize);
         if (H->theCells == NULL)
                   handlError("malloc for H->theCells is error");

         for (i = 0; i < H->TableSize; i++)
                   H->theCells[i].info = Empty;
         return H;
}


unsigned int 
Find(char* key, HashTable *H)
{
        unsigned int Pos;
        int collisionNum;
        collisionNum = 0;
        Pos = Hash(key,H->TableSize);
        while (H->theCells[Pos].info != Empty && H->theCells[Pos].value != key)
        {
                Pos = Pos + 2 * ++collisionNum - 1;
                if (Pos >= H->TableSize)
                         Pos -= H->TableSize;
         }
        return Pos;
}


void 
Insert(char* key, HashTable *H)
{
         unsigned int Pos;

         Pos = Find(key,H);
         if (H->theCells[Pos].info != Legitimate)
         {
                   H->theCells[Pos].info = Legitimate;
                   H->theCells[Pos].value = key;
         }
}

HashTable* 
Rehash(HashTable *H)   //再散列
{
        int i, oldSize;
        HashEntry *oldCells;
        oldCells = H->theCells;
        oldSize = H->TableSize;

        H = InitializeTable(2*oldSize);
        for (i = 0; i < oldSize; i++)
             if (oldCells[i].info == Legitimate)
                          Insert(oldCells[i].value,H);
        free(oldCells);
        return H;
}

void 
handlError(char *msg)
{
        fputs(msg,stderr);
        fputc('\n',stderr);
        exit(1);
}
原创粉丝点击