数据结构-哈希查找(代码实现注释超详细哦)

哈希查找(代码实现 注释超详细哦)

 

什么是理想的哈希表呢。哈希表(通常用数组来存放这张表)中记录的存储位置和他的关键字之间有一个确定的对应关系f(key),这就是哈希函数,常见的哈希函数;

  • 直接定制法,除留余数法

它使每一个关键字和结构中唯一一个存储位置相对应。因而查找时可以根据f(key)算出要查找关键字的位置,达到快速查找的目的(不需要比较查找效率可达到O(1))。但是这是一种很理想的情况,实际上在应用中会有这种情况的产生;

    • 多个元素通过相同的哈希函数——》计算出相同的哈希地址—-〉产生哈希冲突(原位置被占)
    • 那么如何解决哈希冲突?
    • 1》检查哈希函数设计是否合理?
    • 2》哈希函数的值域必须在哈希表的范围内
    • 3》尽量使哈希地址分散。(其中一种方法就是二次探测)

      当已经发生时;

      4》从发生哈希冲突的位置开始,向后找下一个“哈希地址”。(逐个超后探测,线型探测)缺陷;存在数据堆积。防治方法(二次探测)

       

如下是我实现的代码

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

typedef enum {EX,EM,DL}State;//储存位置的状态,是已存,空,还是删除过,在这个哈希表中删除过元素的存储空间是不可再用的
typedef int DataType;

typedef struct HTELEM {
        DataType  _data;//存入的关键字(关键字不一定是数值,当然目前我们做的这个表中存的是数值)
        State _state;
}HTELEM;


typedef struct HashTable{
        HTELEM*  arr;//存放哈希表的数组
        int _capacity;//数组的容量
        int _size;//已用存储位置的大小
        int _IsLineDetective;//标志着选择的哈希函数
}HT,HashTable;


void   swap (HT*ht,HT*newht)//交换两个哈希表的内容
{
        int temp=0;
        temp=(int)ht->arr;
        ht->arr=newht->arr;
        newht->arr=(HTELEM*)temp;



        temp=ht->_capacity;
        ht->_capacity=newht->_capacity;
        newht->_capacity=temp;

        temp=ht->_size;
        ht->_size=newht->_size;
        newht->_size=temp;

        temp=ht->_IsLineDetective;
        ht->_IsLineDetective=newht->_IsLineDetective;
        newht->_IsLineDetective=temp;
}

void HashTableInit(HT*ht ,int capacity,int IsLineDetectiev)//初始化哈希表
{
        int i=0;
        ht->arr=(HTELEM*)malloc(sizeof(HTELEM)*capacity);//给存放哈希表的数组动态开辟内存
        for (i=0;i<capacity;i++)//所有位置的储存状态置为空
        {
                ht->arr[i]._state=EM;
        }

        ht->_size=0;
        ht->_IsLineDetective=IsLineDetectiev;
        ht ->_capacity=capacity;
}


int HashFunc (DataType  data, HT*ht)
{
        return    data%ht->_capacity;//哈希函数;除留余数法
}

int DetectiveLine(int hashaddr,HT*ht)//一次线型探测
{
        hashaddr++;
        if (hashaddr==ht->_capacity)
                hashaddr=0;
        return hashaddr;
}

int Detective2(int hashaddr,int i,HT*ht)//二次(平方)探测
{
        hashaddr=hashaddr+2*i+1;
        if (hashaddr>=ht->_capacity)
                hashaddr%=ht->_capacity;
        return hashaddr;
}

void HashTableInsert (HT *ht ,DataType data)//哈希表的插入
{
        int i=0;
        int hashaddr=-1;
        assert (ht);


        CheckCapacity(ht);//查看并决定是否需要扩容


        hashaddr=HashFunc(data,ht);//通过哈希函数计算应插位置

        while (EM!=ht->arr[hashaddr]._state)
        {
                if (ht->arr[hashaddr]._state==EX)
                {
                        if (ht->arr[hashaddr]._data==data)//已经有这个数据就不用插入,直接返回
                                return;
                }
                if (ht->_IsLineDetective)//当前的位置被占(被不是要插的数据占),或被删除过,则不可用(哈希冲突),向后探测
                {
                        hashaddr=DetectiveLine(hashaddr,ht);
                }
                else {
                        ++i;
                        hashaddr=Detective2(hashaddr,i,ht);
                }

        }

        ht ->arr[hashaddr]._state=EX;//向已经找到的位置,放入数据
        ht->arr[hashaddr]._data=data;
        ht->_size++;
}



int HashTableFind (HT*ht,DataType data)//在哈希表中查找数据,与插入相似
{
        int hashaddr=-1,startaddr=-1,i=0;
        assert(ht);
        hashaddr =HashFunc(data,ht);
        startaddr=hashaddr;//记录开始查找位置(既不发生哈希冲突时应存位置)

        while (EM!=ht->arr[hashaddr]._state)
        {
                if (ht->arr[hashaddr]._state==EX)//找到返回
                        if (ht->arr[hashaddr]._data==data)
                                return    hashaddr;

                if (ht->_IsLineDetective)//向后查找
                {
                        hashaddr=DetectiveLine(hashaddr,ht);
                        if (hashaddr==startaddr)
                                return -1;
                }
                else {
                        ++i;
                        hashaddr=Detective2(hashaddr,i,ht);
                        if (hashaddr==startaddr)
                                return -1;

                }
        }
        return -1;
}



void HashTableDelete(HT* ht ,DataType   data)//哈希表的删除
{

        int ret=-1;
        assert (ht);

        ret =HashTableFind(ht,data);

        if (ret!=-1)
        {
                ht->arr[ret]._state=DL;
                ht->_size--;
        }
}

int HashTableSize(HT*ht)//哈希表的大小
{
        assert (ht);
        return ht->_size;
}


int HashTableEmpty(HT*ht)//哈希表是否为空
{
        assert (ht);
        if (  0==ht->_size)
                return 1;
}


void HashTableDestory(HT*ht)//哈希表的销毁

{
        int i=0;
        free(ht->arr);
        ht->arr=NULL;
        ht->_size=0;
        ht->_IsLineDetective=0;
        ht ->_capacity=0;
}

int CheckCapacity(HT*ht)//哈希表的扩容
{
        int i=0;
        int capacity;
        assert (ht );
        if (ht->_size*10/ht->_capacity>7)//当已用空间占到总容量的70%时扩容
        {
                HT newht;
                capacity=ht->_capacity*2;
                HashTableInit(&newht ,capacity,ht->_IsLineDetective);//初始化一个新表,(新表的容量是老表的2倍)

                for (i=0;i<ht->_capacity;i++)//把老表中的元素插入新表
                {
                        if (EX==ht->arr[i]._state)
                                HashTableInsert (&newht ,ht->arr[i]._data);
                }
                swap(&newht,ht);//把新表的内容交给老表(新表只是一个函数体内的变量,除了函数体会被销毁)
                HashTableDestory(&newht);//销毁新表
        }
        return 1;
}




void TestHashTable()
{
        HashTable ht;
        HashTableInit(&ht,6,1);
        HashTableInsert (&ht ,23);
        HashTableInsert (&ht ,14);
        HashTableInsert (&ht ,74);
        HashTableInsert (&ht ,33);
        HashTableInsert (&ht ,19);
        HashTableInsert (&ht ,29);
        HashTableInsert (&ht ,29);

        printf("size=%d\n",HashTableSize(&ht));
        if (-1!=HashTableFind(&ht,33))
        {
                printf ("have\n");
        }
        else
                printf ("no have\n");
        if (-1!=HashTableFind(&ht,3))
        {
                printf ("have\n");
        }
        else
                printf ("no have\n");


        HashTableDelete(&ht,23);
        printf ("size=%d\n",HashTableSize(&ht));
        if (-1!=HashTableFind(&ht,33))
        {
                printf ("have\n");
        }
        else
                printf ("no have\n");
}


int main ()
{
        TestHashTable();
        return 0;
}
-- INSERT --                                                                                                               258,2         Bot

 

 

这里就完成了我们关于哈希表的代码。大家有什么意见或者建议,或者哪里不清楚可以留言呦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值