哈希之閉散列(線性探測/二次探測)

HashTable.h
#include <assert.h>
#include <stdio.h>
#include <malloc.h>
#include "Common.h"

//哈希表位置的狀態
typedef enum State
{
    EMPTY,  //當前位置爲空
    EXIST,  //當前位置有元素
    DELETE  //檔期那位置被刪除
}State;

typedef int DataType;
//typedef char* DataType;

//轉換Int函數指針
typedef size_t(*PDT)(DataType str);

//鍵值對
typedef struct Elem
{
    DataType _data;
    State _state;
}Elem;

typedef enum 
{
    _IsLine,            //線性探測
    _IsNotLine      //二次探測
}IsLine;


//哈希表
typedef struct HashTable
{
    Elem * _table;      
    int _capacity;      //容量
    int _size;      //EX的個數
    int _total;         //EX/DE總共的個數
    IsLine _Dete;           //探測方法
    PDT  _setData;      //將數據轉化爲整型,
}HashTable;


//初始化
void HashTableInit(HashTable * ht, int capacity, IsLine _Dete, PDT setData);

//插入
void HashTableInsert(HashTable *ht, DataType data);

//刪除
void HashTableDelete(HashTable *ht, DataType data);

//查找
int HashTableFind(HashTable *ht, DataType data);

//元素個數
int HashTableSize(HashTable *ht);

//判空
int HashTableEmpty(HashTable *ht);

// 銷燬哈希表
void HashTableDestory(HashTable* ht);

/////////////////////////////////////////////
//輔助方法

//哈希函數
int HashFunc(HashTable* ht, int data);
//線性探測
int IsLineDete(HashTable* ht, int HashAddr);
//二次探測
int DeteTwo(HashTable * ht, int HashAddr, int i);

//測試

void TestHashData();
void TestHashStr();

HashTable.c

#include "HashTable.h"



//初始化
void HashTableInit(HashTable * ht, int capacity, IsLine Dete, PDT setData)
{
    assert(ht);

    capacity = GetCapacity(capacity);
    ht->_table = (Elem*)malloc(sizeof(Elem)*capacity);

    if (NULL == ht->_table)
        return;

    for (int i = 0; i < capacity; i++)
        ht->_table[i]._state = EMPTY;

    ht->_capacity = capacity;
    ht->_size = 0;
    ht->_total = 0;
    ht->_setData = setData;
    ht->_Dete = Dete;
}



//檢測容量
int CheckCapacity(HashTable *ht)
{
    if ((ht->_total) * 10 / (ht->_capacity) > 7)
        return 1;

    return 0;
}

//交換
void _Swop(int * newht, int* oldht)
{
    int temp = *newht;
    *newht = *oldht;
    *oldht = temp;
}


void Swop(HashTable* newht, HashTable* oldht)
{
    Elem * pTemp = newht->_table;
    newht->_table = oldht->_table;
    oldht->_table = pTemp;

    _Swop(&newht->_capacity, &oldht->_capacity);
    _Swop(&newht->_size, &oldht->_size);
    _Swop(&newht->_total, &oldht->_total);

}


//擴容
void BuyCapacity(HashTable * ht)
{
    assert(ht);

    HashTable newht;
    int NewCapacity = GetCapacity(ht->_capacity);

    //初始化新的哈希表
    HashTableInit(&newht, NewCapacity, ht->_Dete, ht->_setData);

    //拷貝元素
    for (int i = 0; i < ht->_capacity; ++i)
    {
        if (ht->_table[i]._state == EXIST)
            HashTableInsert(&newht, ht->_table[i]._data);
    }

    //交換
    Swop(&newht, ht);
    HashTableDestory(&newht);
}

//插入
void HashTableInsert(HashTable *ht, DataType data)
{
    int HashAddr = 0;
    int i = 0;
    assert(ht);

    //判斷負載因子,檢測容量
    if (CheckCapacity(ht))
    {
        BuyCapacity(ht);
    }

    int Newdata = ht->_setData(data);
    HashAddr = HashFunc(ht, Newdata);


    while (EMPTY != ht->_table[HashAddr]._state)
    {

        if (ht->_table[HashAddr]._state == EMPTY)
        {
            if (ht->_table[HashAddr]._data == data)
                return;
        }


        if (ht->_Dete == _IsLine)
            HashAddr = IsLineDete(ht, HashAddr);
        else
            HashAddr = DeteTwo(ht, HashAddr, ++i);
    }

    //說明狀態爲空,可以直接插入
    ht->_table[HashAddr]._state = EXIST;
    ht->_table[HashAddr]._data = data;
    ht->_size++;
    ht->_total++;
}


//查找元素,找到返回地址
int HashTableFind(HashTable * ht, DataType data)
{
    int HashAddr = 0;
    int StartAddr = 0;
    int i = 0;
    assert(ht);

    int Newdata = ht->_setData(data);
    HashAddr = HashFunc(ht, Newdata);

    StartAddr = HashAddr;

    while (EMPTY != ht->_table[HashAddr]._state)
    {
        if (ht->_table[HashAddr]._state == EXIST)
        {
            if (ht->_table[HashAddr]._data == data)
                return HashAddr;
        }

        //線性探測
        if (ht->_Dete == _IsLine)

        {
            HashAddr = IsLineDete(ht, HashAddr);
            //找一圈都沒找到,退出
            if (HashAddr == StartAddr)
                return -1;

        }
        else//二次探測
            HashAddr = DeteTwo(ht, HashAddr, ++i);

    }

    return -1;
}


//刪除
void HashTableDelete(HashTable *ht, DataType data)
{
    assert(ht);
    if (-1 == HashTableFind(ht, data))
        return;

    ht->_table[HashTableFind(ht, data)]._state = DELETE;

    ht->_size--;
}


//元素個數
int HashTableSize(HashTable *ht)
{
    assert(ht);

    return ht->_size;
}

//判空
int HashTableEmpty(HashTable *ht)
{
    assert(ht);

    if (0 == ht->_size)
        return 1;

    return 0;
}


// 銷燬哈希表
void HashTableDestory(HashTable* ht)
{
    assert(ht);
    free(ht->_table);
    ht->_table = NULL;
    ht->_capacity = 0;
    ht->_size = 0;
    ht->_total = 0;
}



//哈希函數
int HashFunc(HashTable* ht, int data)
{
    assert(ht);

    return data % (ht->_capacity);
}


//線性探測
int IsLineDete(HashTable* ht, int HashAddr)
{

    HashAddr = HashAddr + 1;
    if (HashAddr == ht->_capacity)//如果越界
        HashAddr = 0;

    return HashAddr;
}

//二次探測
int DeteTwo(HashTable * ht, int HashAddr, int i)
{
    HashAddr = HashAddr + 2 * i + 1;

    //越界
    if (HashAddr >= ht->_capacity)
        HashAddr %= ht->_capacity;
    return HashAddr;
}


void TestHashData()
{
    HashTable ht;
    HashTableInit(&ht, 10, _IsLine, DataToInt);
    HashTableInsert(&ht, 5);
    HashTableInsert(&ht, 9);
    HashTableInsert(&ht, 13);
    HashTableInsert(&ht, 10);
    HashTableInsert(&ht, 2);
    HashTableInsert(&ht, 13);
    HashTableInsert(&ht, 10);
    HashTableInsert(&ht, 2);
    HashTableInsert(&ht, 8);
    int size = HashTableSize(&ht);
    DataType data = ht._table[HashTableFind(&ht, 9)]._data;

    HashTableDelete(&ht, 13);//刪除
    size = HashTableSize(&ht);

    HashTableDestory(&ht);
}


#if 0
void TestHashStr()
{
    HashTable ht;
    HashTableInit(&ht, 10, _IsLine, StrToInt);
    HashTableInsert(&ht, "b");
    HashTableInsert(&ht, "ca");
    HashTableInsert(&ht, "a");
    HashTableInsert(&ht, "ac");

    int size = HashTableSize(&ht);
    DataType data = ht._table[HashTableFind(&ht, "ac")]._data;

    HashTableDelete(&ht, "a");//刪除
    size = HashTableSize(&ht);

    HashTableDestory(&ht);
}
#endif

Common.c

#include "Common.h"

int GetCapacity(size_t capacity)
{
    int i = 0;
    for (; i < 28; i++)
    {
        if (capacity < _PrimeList[i])
            return _PrimeList[i];
    }

    return _PrimeList[27];
}

//將字符串轉換爲整數
size_t StrToInt(const char * str)
{
    unsigned int seed = 131; // 31 131 1313 13131 131313
    unsigned int hash = 0;
    while (*str)
    {
        hash = hash * seed + (*str++);
    }
    return (hash & 0x7FFFFFFF);
}

//整形轉無符號整形
size_t DataToInt(int data)
{
    return data;
}

Common.h



#pragma once

#define  size_t unsigned long
#define  _PrimeSize 28

static const unsigned long _PrimeList[_PrimeSize] =
{
    53ul, 97ul, 193ul, 389ul, 769ul,
    1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
    49157ul, 98317ul, 196613ul, 393241ul, 786433ul,
    1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul,
    50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul,
    1610612741ul, 3221225473ul, 4294967291ul
};

//用來獲取容量,使每次都是素數
int GetCapacity(size_t capacity);

size_t StrToInt(const char * str);

size_t DataToInt(int data);
發佈了82 篇原創文章 · 獲贊 30 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章