哈希表--开散列(哈希桶,拉链法)

functions.h

#include<stdio.h>
#include<assert.h>
#include<windows.h>

typedef int KeyType;//关键字类型
typedef int ValueType;//个数类型

typedef struct HashNode //哈希链式节点
{
    KeyType _key;//关键字值
    ValueType _value;//个数
    struct HashNode* _next;//指向下个节点的指针
}HashNode;

typedef struct HashTable//哈希表
{

    HashNode** _tables;   // hashnode *表示数组内每个元素类型 ,*table表示数组
    size_t _size;//数组内已用个数
    size_t _capacity;//数组最大容量
}HashTable;

HashNode* BuyHashNode(KeyType key, ValueType value)
{
    HashNode *newnode = (HashNode*)malloc(sizeof(HashNode));
    assert(newnode);
    newnode->_key = key;
    newnode->_next = NULL;
    newnode->_value = value;
    return newnode;
}
void HashPrint(HashTable *ht)
{
    assert(ht);
    for (size_t i = 0;i < ht->_capacity;i++)
    {

        HashNode *cur = ht->_tables[i];
        printf("%d:", i);
        while (cur)
        {
            printf("[%d %d]->", cur->_key, cur->_value);
            cur = cur->_next;
        }
        printf("NULL\n");

    }
}
size_t HashFunc(KeyType key, size_t capacity)
{
    return key % capacity;
}
size_t GetNextPrimeNum(size_t cur)
{
    int i = 0;
    const int _PrimeSize = 28;
    static const unsigned long _PrimeList[28] =
    {
        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
    };
    for (int i = 0;i < 28;i++)
    {
        if (_PrimeList[i] >(unsigned long)cur)
        {
            return _PrimeList[i];
        }
    }
    return _PrimeList[i];

}
void HashTableInit(HashTable* ht, size_t capacity)
{
    assert(ht);
    ht->_tables = (HashNode**)malloc(sizeof(HashNode*)*capacity);
    assert(ht->_tables);
    ht->_size = 0;
    ht->_capacity = capacity;
    //注意每个数组元素要设置为NULL
    for (size_t i = 0;i < ht->_capacity;i++)
    {
        ht->_tables[i] = NULL;
    }
}
void HashTableDestory(HashTable* ht)
{
    assert(ht);
    for (size_t i = 0;i < ht->_capacity;i++)
    {
        HashNode *cur = ht->_tables[i];
        while (cur)
        {
            HashNode *next = cur->_next;
            free(cur);
            cur = next;
        }
    }
    free(ht->_tables);
    ht->_size = ht->_capacity = 0;

}
void check_capacity(HashTable *ht)
{
    assert(ht);
    if (ht->_size == ht->_capacity)//扩容条件
    {
        HashTable newtable;
        HashTableInit(&newtable, GetNextPrimeNum(ht->_capacity));
        for (size_t i = 0;i < ht->_capacity;i++)//依次将旧表的数据指向新表的映射点
        {
            HashNode *cur = ht->_tables[i];
            while (cur)
            {
                HashNode *next = cur->_next;
                size_t index = HashFunc(cur->_key, newtable._capacity);
                cur->_next = newtable._tables[index];
                newtable._tables[index] = cur;
                cur = next;
            }
        }
        //完成扩容+转移后,仍然使用旧表ht;
        HashTableDestory(ht);
        ht->_tables = newtable._tables;
        ht->_size = newtable._size;
        ht->_capacity = newtable._capacity;

    }
}
void HashTableInsert(HashTable* ht, KeyType key, ValueType value)
{
    assert(ht);
    //检查是否需要扩容
    check_capacity(ht);
    //求映射点
    size_t index = HashFunc(key, ht->_capacity);
    //判断该key值已经在哈希表中
    HashNode *cur = ht->_tables[index];
    while (cur)
    {
        if (cur->_key == key)
        {
            cur->_value++;
            return;

        }
        cur = cur->_next;
    }
    HashNode *newnode = BuyHashNode(key, value);
    newnode->_next = ht->_tables[index];
    ht->_tables[index] = newnode;
    ht->_size++;
}
HashNode* HashTableFind(HashTable* ht, KeyType key)
{
    assert(ht);
    size_t index = HashFunc(key, ht->_capacity);
    HashNode *cur = ht->_tables[index];
    while (cur)
    {
        if (cur->_key == key)
        {
            return cur;
        }
        cur = cur->_next;
    }
    printf("can not find the key!\n");
    return NULL;

}
//成功删除返回1 ,删除失败返回0;
int HashTableRemove(HashTable* ht, KeyType key)
{
    //找映射点,变成从单链表中删除一个节点,删除时检查该key值得
    //value值,如果>1的话减1,如果等于1直接删除。
    assert(ht);
    size_t index = HashFunc(key, ht->_capacity);
    HashNode *cur = ht->_tables[index];
    while (cur)
    {
        if (cur->_key == key)
        {
            if (cur->_value > 1)
            {
                cur->_value--;
                return 1;
            }
            if (cur->_next)
            {
                //要删除的节点value值为1且不是尾节点,可以使用替换法
                HashNode *next = cur->_next;
                cur->_key = next->_key;
                cur->_value = next->_value;
                cur->_next = next->_next;
                free(next);
                next = NULL;
                return 1;
            }
            else
            {
                //说明要删除的节点是尾节点且value值为1
                HashNode *pcur = ht->_tables[index];

                if (pcur = cur)
                {
                    //说明该哈希地址出只有1个节点且是要删除的那个
                    free(pcur);
                    ht->_tables[index] = NULL;
                    return 1;
                }
                while (pcur->_next != cur)
                {
                    pcur = pcur->_next;
                }
                pcur->_next = NULL;
                free(cur);
                cur = NULL;
                return 1;

            }
        }
        cur = cur->_next;

    }
    return 0;//没有找到
}

test.c

#include"functions.h"

void test()
{
    HashTable ht;
    HashTableInit(&ht, 13);

    HashTableInsert(&ht, 14, 2);
    HashTableInsert(&ht, 27, 1);
    HashTableInsert(&ht, 1, 1);
    HashTableInsert(&ht, 3, 1);

    HashPrint(&ht);
    printf("\n\n");
    HashTableRemove(&ht,14);



    HashPrint(&ht);



}

int main()
{
    test();
    system("pause");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Ferlan/article/details/80539241