哈希表之开散列

了解哈希基本看概念请看这里:搜索结构之哈希
开散列完整代码:开散列

开散列每一个地址的底层实现像一个个的桶,所以又叫哈希桶,同一个桶中存放哈希冲突的元素。

通常,每个桶对应的链表结点都很少,将n个关键码通过某一个散列函数,存放到散列表中的m个桶中,那么每一个桶中链表的平均长度为n/m,以搜索平均长度为n/m的链表代替搜索长度为n的顺序表,搜索效率快的多。

应用链地址法处理溢出,需要增设链接指针,似乎增加了存储开销。事实上:
由于开地址法必须保持大量的空闲空间以确保搜索效率,如二次探查法要求装载因子a <= 0.7,而表项所占空间又比指针大的多,
所以使用链地址法反而比开地址法节省存储空间。

头文件

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<assert.h>

#define size_t unsigned long

typedef char* DataType;

typedef size_t(*PDT)(DataType data);

typedef struct Node
{
    struct  Node* _pNext;
    DataType data;
}Node,*PNode;

//哈希表
typedef struct HashBucket
{
    PNode* _table;
    int _capacity;
    int _size;
    PDT _setData;
}HashBucket;

//哈希桶初始化
void HashInit(HashBucket* ht, int capacity, PDT _setData);

//数据唯一的插入与删除
void HashBuctetInsertUnique(HashBucket* ht, DataType data);
void HashBucketDeleteUnique(HashBucket* ht, DataType data);

//数据不唯一
void HashBuctetInsert(HashBucket* ht, DataType data);
void HashBucketDelete(HashBucket* ht, DataType data);

//查找
PNode HashBucketFind(HashBucket* ht, DataType data);

//元素个数
int HashBucketSize(HashBucket* ht);

//销毁
void DestroyHashBuctet(HashBucket* ht);

//////////////////////////////////////////////

//哈希函数
int HashFunc(HashBucket* ht, int data);

//创建新结点
PNode BuyNode(DataType data);
//打印
void HashBucketPrint(HashBucket* ht);

size_t StrToInt(const char* str);

size_t DataToInt(int data);

功能实现部分

#include"HashBucket.h"

//哈希桶初始化
void HashInit(HashBucket* ht, int capacity, PDT _setData)
{
    assert(ht);

    ht->_table = (PNode*)malloc(sizeof(Node)*capacity);
    if (NULL == ht->_table)
        assert(0), exit(1);

    ht->_capacity = capacity;
    ht->_size = 0;
    ht->_setData = _setData;
    for (int i = 0; i < ht->_capacity; ++i)
    {
        ht->_table[i] = NULL;
    }
}

//数据唯一的插入
void HashBuctetInsertUnique(HashBucket* ht, DataType data)
{
    int HashAddr = -1;
    assert(ht);

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

    PNode pCur = ht->_table[HashAddr];

    while (pCur)
    {
        if (pCur->data == data)
            return;
        else
            pCur = pCur->_pNext;
    }

    pCur = BuyNode(data);

    pCur->_pNext = ht->_table[HashAddr];
    ht->_table[HashAddr] = pCur;
    ++ht->_size;
}
//数据唯一的删除
void HashBucketDeleteUnique(HashBucket* ht, DataType data)
{
    assert(ht);
    int HashAddr = -1;
    PNode pPre = NULL;
    PNode pCur = NULL;

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

    //空桶
    if (NULL == ht->_table[HashAddr])
        return;

    pPre = ht->_table[HashAddr];
    pCur = ht->_table[HashAddr];

    //头结点的值和data相等
    if (pCur->data == data)
    {
        ht->_table[HashAddr] = pCur->_pNext;
        free(pCur);
        --ht->_size;
        return;
    }

    while (pCur)
    {
        if (pCur->data == data)
        {
            break;
        }
        else
        {
            pPre = pCur;
            pCur = pCur->_pNext;
        }
    }

    //判断pCur是否找到了data,退出可能是找到了,或pCur为空
    if (pCur)
    {
        pPre->_pNext = pCur->_pNext;
        free(pCur);
        --ht->_size;
    }
}

//数据不唯一
//数据相同插入
void HashBuctetInsert(HashBucket* ht, DataType data)
{
    int HashAddr = -1;
    assert(ht);

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

    //头插
    PNode pCur = BuyNode(data);
    pCur->_pNext = ht->_table[HashAddr];
    ht->_table[HashAddr] = pCur;
    ht->_size;
}
//删除所有值为data的元素
void HashBucketDelete(HashBucket* ht, DataType data)
{
    int HashAddr = -1;
    PNode pPre = NULL;
    PNode pCur = NULL;
    assert(ht);

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

    //空桶
    if (NULL == ht->_table[HashAddr])
        return;

    pPre = ht->_table[HashAddr];
    pCur = ht->_table[HashAddr];

    //data值与哈希中的data相等
    while (pCur&&pCur->data == data)
    {
        ht->_table[HashAddr] = pCur->_pNext;
        free(pCur);
        --ht->_size;

        pCur = ht->_table[HashAddr];
    }

    //后续不为空
    while (pCur)
    {
        if (pCur->data == data)
        {
            pPre->_pNext = pCur->_pNext;
            --ht->_size;
            free(pCur);

            pCur = pPre->_pNext;
        }
        else
        {
            pPre = pCur;
            pCur = pCur->_pNext;
        }
    }
}

//查找
PNode HashBucketFind(HashBucket* ht, DataType data)
{
    int HashAddr = -1;
    assert(ht);

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

    PNode pCur = ht->_table[HashAddr];
    while (pCur)
    {
        if (pCur->data == data)
            break;
        else
            pCur = pCur->_pNext;
    }

    return pCur;
}

//元素个数
int HashBucketSize(HashBucket* ht)
{
    return ht->_size;
}

//销毁
void DestroyHashBuctet(HashBucket* ht)
{
    assert(ht);

    PNode pDel = NULL;
    int i = 0;
    for (; i < ht->_capacity; ++i)
    {
        pDel = ht->_table[i];
        while (pDel)
        {
            ht->_table[i] = pDel->_pNext;
            free(pDel);
            pDel = ht->_table[i];
        }
    }

    free(ht->_table);
    ht->_size = 0;
    ht->_capacity = 0;
}

//

//哈希函数
int HashFunc(HashBucket* ht, int data)
{
    assert(ht);

    return data % (ht->_capacity - 1);
}

//创建新结点
PNode BuyNode(DataType data)
{
    PNode pNewNode = NULL;
    pNewNode = (PNode)malloc(sizeof(Node));
    if (NULL == pNewNode)
        return NULL;

    pNewNode->data = data;
    pNewNode->_pNext = NULL;

    return pNewNode;
}
//打印
void HashBucketPrint(HashBucket* ht)
{
    PNode pCur = NULL;
    assert(ht);
    int i = 0;

    for (; i < ht->_capacity; ++i)
    {
        printf("Hash Bucket%ld: ", i);
        pCur = ht->_table[i];
        while (pCur)
        {
            if (ht->_setData == DataToInt)
            {
                printf("%d\t", pCur->data);
            }
            else
            {
                printf("%s\t", pCur->data);
            }
            pCur = pCur->_pNext;
        }
        printf("\n");
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值