数据结构——散列

分离链式法

#include<stdio.h>
#include<stdlib.h>
#define MinTableSize (10)

#ifndef _HashSep_H

typedef int ElementType;

typedef unsigned int Index;

struct ListNode;
typedef struct ListNode* Position;

struct HashTbl;
typedef struct HashTbl* HashTable;

Index Hash(int 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);


#endif

struct ListNode
{
    ElementType Element;
    Position Next;
};

typedef Position List;

struct HashTbl
{
    int TableSize;
    List *TheLists;
};

Index Hash(int Key, int TableSize)
{
    return Key % TableSize;
}

// 返回大于N的最小素数
static int NextPrime(int N)
{
    int i;

    if (N % 2 == 0)
        N++;

    for ( ; ; N += 2)
    {
        for (i = 3; i * i <= N; i+= 2)
        {
            if (N % i == 0)
                break;
        }
        return N;
    }
}

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

    // 合法性检查
    if (TableSize < MinTableSize)
    {
        printf("Table size too small");
        return NULL;
    }

    // 分配散列表的空间
    H = (struct HashTbl*)malloc(sizeof(struct HashTbl));
    if (NULL == H)
    {
        printf("H is NULL");
        return NULL;
    }

    H->TableSize = NextPrime(TableSize);

    // 分配链表的总空间大小
    H->TheLists =(List*) malloc(sizeof(List) * H->TableSize);
    
    if (NULL == H)
    {
        printf("H is NULL");
        return NULL;
    }

    // 初始化散列表中链表头的大小
    for (i = 0; i < H->TableSize; i++)
    {
        H->TheLists[i] = (struct ListNode*)malloc(sizeof(struct ListNode));
        if (NULL == H->TheLists[i])
        {
            printf("H is NULL");
            return NULL;
        }
        else
        {
            H->TheLists[i]->Next = NULL;
        }
    }

    return H;
}

// 查找操作
// 返回关键字Key所在的位置,而不是槽的位置
Position Find(ElementType Key, HashTable H)
{
    Position P;
    List L;

    // 通过散列函数查找到关键字Key所在的槽的位置
    L = H->TheLists[Hash(Key, H->TableSize)];
    P = L->Next;

    // 链表中的查找
    while(P != NULL && P->Element != Key)
    {
        P = P->Next;
    }

    return P;
}

// 插入操作
void Insert(ElementType Key, HashTable H)
{
    Position Pos, NewCell;
    List L;

    // 查找关键字Key是否在散列在散列表中
    Pos = Find(Key, H);
    if (NULL == Pos) // Key不在散列表中
    {
        NewCell = (struct ListNode*)malloc(sizeof(struct ListNode));
        if (NULL == NewCell)
        {
            printf("Distribute failed!");
            return;
        }
        else
        {
            // 确定关键字Key要散列到的槽位
            L = H->TheLists[Hash(Key, H->TableSize)];
            // 插入该链表的最前面
            NewCell->Next = L->Next;
            NewCell->Element = Key;
            L->Next = NewCell;
        }
    }
}

// 释放散列表
void DestroyTable(HashTable H)
{
    int i;

    for (i = 0; i < H->TableSize; i++)
    {
        Position P = H->TheLists[i];
        Position Tmp;

        // 释放链表
        while(P != NULL)
        {
            Tmp = P->Next;
            free(P);
            P = Tmp;
        }
    }

    free(H->TheLists);
    free(H);
}

// 返回存放在位置P处的元素
ElementType Retrieve(Position P)
{
    return P->Element;
}

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

开放寻址法

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

#define MinTableSize 10

#ifndef _HashSep_H

typedef int ElementType;

typedef unsigned int Index;

typedef Index Position;

struct HashTbl;
typedef struct HashTbl* HashTable;

Index Hash(int 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 Rehash(HashTable H);

#endif

enum KindOfEntry {Legitimate, Empty, Deleted};

// 解决开放寻址法中删除操作的困难
// 将散列表中的每个槽位都进行标记:legitimate empty deleted
struct HashEntry
{
    ElementType Element;
    enum KindOfEntry Info;
};

typedef struct HashEntry Cell;

// 散列表结构
struct HashTbl
{
    int TableSize;
    Cell* TheCells;
};

// 返回大于N的最小素数
static int NextPrime(int N)
{
    int i;

    if (N % 2 == 0)
        N++;

    for ( ; ; N += 2)
    {
        for (i = 3; i * i <= N; i+= 2)
        {
            if (N % i == 0)
                break;
        }
        return N;
    }
}

// 散列函数
Index Hash(ElementType Key, int TableSize)
{
    return Key % TableSize;
}

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

    if (TableSize < MinTableSize)
    {
        printf("Table size too small!");
        return NULL;
    }

    // 分配散列表的空间
    H = (struct HashTbl*)malloc(sizeof(struct HashTbl));
    if (NULL == H)
    {
        printf("H is NULL");
        return NULL;
    }

    H->TableSize = NextPrime(TableSize);

    H->TheCells = (Cell*)malloc(sizeof(Cell) * H->TableSize);
    if (NULL == H->TheCells)
    {
        printf("H->TheCells is NULL");
        return NULL;
    }

    // 将散列表中每个槽的状态标记为empty
    for(i = 0; i < H->TableSize; i++)
    {
        H->TheCells[i].Info = Empty;
    }

    return H;
}


// 查找操作  
Position Find( ElementType Key, HashTable H )  
{  
    Position CurrentPos;  
    int CollisionNum;  

    CollisionNum = 0;  
    CurrentPos = Hash( Key, H->TableSize );  
    while ( H->TheCells[ CurrentPos ].Info != Empty &&  
        H->TheCells[ CurrentPos ].Element != Key )  
        /* Probably need strcpy! */  
    {  
        CurrentPos += 2 * ++CollisionNum - 1;   // 若该位置不是Empty且存放的关键字不是key,查找下一个
        if ( CurrentPos >= H->TableSize )  
            CurrentPos -= H->TableSize;  
    }  
    return CurrentPos;  
}  

// 插入操作  
void Insert( ElementType Key, HashTable H )  
{  
    Position Pos;  

    Pos = Find( Key, H );  
    if ( H->TheCells[ Pos ].Info != Legitimate )  // 只要该位置不是Legitimate,就可以插入
    {  
        /* Ok to insert here */  
        H->TheCells[ Pos ].Info = Legitimate;  
        H->TheCells[ Pos ].Element = Key; /* Probably need strcpy! */  
    }  
}  

// 更新  
HashTable Rehash( HashTable H )  
{  
    int i, OldSize;  
    Cell *OldCells;  

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

    /* Get a new, empty table */  
    H = InitializeTable( 2 * OldSize );  

    /* Scan through old table, reinserting into new */  
    for( i = 0; i < OldSize; i++ )  
        if ( OldCells[ i ].Info == Legitimate )  
            Insert( OldCells[ i ].Element, H );  

    free( OldCells );  

    return H;  
}  


ElementType Retrieve( Position P, HashTable H )  
{  
    return H->TheCells[ P ].Element;  
}  

void  
DestroyTable( HashTable H )  
{  
    free( H->TheCells );  
    free( H );  
}

int main()
{
    system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青云遮夜雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值