开放定址法实现散列表

     使用分离链接法实现散列表时需要额外的空间来存储指针,而且需要给新单元动态分配空间,导致算法的速度减慢。开放定址法一次分配表的大小,可以使用线性散列,平方散列,双重散列等等方法,这些方法除了散列函数不相同之外,对于散列表的大小要求也不一样。平方散列需要使表的大小是存储元素的两倍以上,这样总能找到空槽来存放产生冲突的元素。(算法导论上有详细证明。)

      下面程序使用的是平方探测散列:

/*
 * hash.h
 *
 *  Created on: Dec 12, 2016
 *      Author: csf
 */

#ifndef HASH_H_
#define HASH_H_

#define MAXTABLESIZE 200
#define MINTABLESIZE 1

typedef unsigned int Index;
typedef Index Position;
typedef int ElementType;

struct HashTbl;
typedef struct HashTbl *HashTable;

int IsPrime(int x);
int NextPrime(int y);
int Hash(ElementType key,int TableSize);
HashTable InitializeTable(int TableSize);
void DestroyTable(HashTable H);
Position Find(ElementType key,HashTable H);
void Insert(ElementType key,HashTable H);
ElementType Retrieve(Position P,HashTable H);
int Delete(ElementType key,HashTable H);
HashTable Rehash(HashTable H);

#endif /* HASH_H_ */

enum KindOfEntry {Legitimate,Empty,Deleted};

struct HashEntry
{
    ElementType Element;
    enum KindOfEntry Info;
};

typedef struct HashEntry Cell;

struct HashTbl
{
    int TableSize;
    Cell *TheCells;
};

源文件:

/*
 * hash.c
 *
 *  Created on: Dec 12, 2016
 *      Author: csf
 */

#include "hash.h"
#include "stdio.h"
#include "stdlib.h"

int IsPrime(int x) //判断素数
{
    int i;
    for(i=2;i*i<x;i++){
        if(x%i==0)
            return 0;
    }
    return 1;
}

int NextPrime(int y) //查找最邻近素数
{
    while(1){
    if(IsPrime(y))
        return y;
    else
        y++;
    }
}

int Hash(ElementType key,int TableSize) //简单取余数的散列函数
{
    return key%TableSize;
}

HashTable InitializeTable(int TableSize) //初始化散列表
{
    HashTable H;
    int i;

    if(TableSize<MINTABLESIZE)
        return NULL;

    H=(struct HashTbl*)malloc(sizeof(struct HashTbl));
    H->TableSize=NextPrime(TableSize);
    if(H==NULL)
        return NULL;
    H->TheCells=malloc(sizeof(Cell)*H->TableSize);
    if(H->TheCells==NULL)
        return NULL;
    for(i=0;i<H->TableSize;i++)
    {
        H->TheCells[i].Info=Empty;
    }
    return H;
}

Position Find(ElementType key,HashTable H) //查找表内元素,没有该元素返回空槽
{
    Position Pos;
    int i;

    i=0;
    Pos=Hash(key,H->TableSize);
    while(H->TheCells[Pos].Info!=Empty && H->TheCells[Pos].Element!=key)//字符串比较用strcmp
    {
        i+=1;
        Pos=Pos+2*i-1;
        if(Pos>=H->TableSize)
            Pos-=H->TableSize;
    }
    return Pos;
}


void Insert(ElementType key,HashTable H) //插入新元素,元素存在则什么也不做
{
    Position Pos;
    Pos=Find(key,H);
    if(H->TheCells[Pos].Info!=Legitimate)
    {
        H->TheCells[Pos].Info=Legitimate;
        H->TheCells[Pos].Element=key;
    }
}

void DestroyTable(HashTable H) //销毁散列表
{
    free(H->TheCells);
    free(H);
}

ElementType Retrieve(Position P,HashTable H) //根据元素位置得到元素值
{
    return H->TheCells[P].Element;
}

int Delete(ElementType key,HashTable H) //删除元素,实际只是把元素标记为deleted
{
    Position TempPos,Pos;
    int i;

    i=0;
    Pos=Hash(key,H->TableSize);
    TempPos=Pos;

    if(H->TheCells[Pos].Element!=key)
    {
        i+=1;
        Pos+=2*i-1;
        if(Pos>H->TableSize)
            Pos-=H->TableSize;
        if(TempPos==Pos)
            return 0;//没有找到该元素,退出避免死循环
    }
    H->TheCells[Pos].Info=Deleted;
    return 1;
}

HashTable Rehash(HashTable H) //再散列,当填充因子大于0.5或者发生冲突无法找到空槽时使用
{
    int i,OldSize;
    Cell *OldCells;

    OldSize=H->TableSize;
    OldCells=H->TheCells;

    H=InitializeTable(2*OldSize);

    for(i=0;i<OldSize;i++)
    {
        if(OldCells[i].Info==Legitimate)
            Insert(OldCells[i].Element,H);
    }
    free(OldCells);
    return H;
}

void main() //测试用例
{
        Position p;

        HashTable table=InitializeTable(30);


        Insert(0,table);
        Insert(1,table);
        Insert(81,table);
        Insert(4,table);
        Insert(64,table);
        Insert(25,table);
        Insert(16,table);
        Insert(36,table);
        Insert(9,table);
        Insert(49,table);


        p=Find(81,table);
        printf("%d \n",table->TheCells[p].Element);


        if(Delete(81,table))
        {
            printf("Deleted\n");
        }

        if(Delete(100,table))
        {
            printf("NoData\n");
        }

        DestroyTable(table);
}




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值