• 散列


    一、散列简介

    1、散列技术:允许以常数时间插入、删除、查找的技术

    2、散列表:包含关键字,具有固定大小的数组。(散列表的实现叫做散列)

    3、散列函数:每个关键字被映射到0到size-1中的某个位置,这个映射叫做散列函数。(散列表的大小一般为素数,减少冲突)

    4、冲突:当两个关键字同时映射到一个位置时,就发生了冲突。

    二、解决冲突的方法

    (一)分离链接法

    1、方法:将散列到同一个值的所有元素保留到一个表中。

    2、散列函数:H(X)=X mod size;

    3、图示: 

    4、代码实现:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    using namespace std;
    const int MAXSIZE = 12000;
    struct Node{
        int data;
        struct Node *next;
    }; 
    typedef struct Node* List;
    typedef List Position;
    
    struct HNode{
        int TableSize;
        List *TheLists;
    };
    typedef struct HNode* HashTable;
    
    bool Is_Prim(int x)
    {
        for(int i=2;i*i<=x;i++)
        if(x%i==0) return false;
        return true;
    }
    int NextPrim(int x)
    {
        while(!Is_Prim(x)) x++;
        return x;
    }
    
    HashTable Init(int size)
    {
        HashTable H;
        int i;
        if(size>MAXSIZE)
        {
            printf("Table if too small!
    ");
            return NULL;
        }
        H=(HashTable)malloc(sizeof(struct HNode));
        if(H==NULL) printf("Out of Space!!!");
        H->TableSize=NextPrim(size);
        H->TheLists=(List*)malloc(sizeof(struct Node)*H->TableSize);
        if(H->TheLists==NULL) printf("Out of Space!!!");
        
        for(i=0;i<H->TableSize;i++)
        {
            H->TheLists[i]=(List)malloc(sizeof(struct Node));
            if(H->TheLists[i]==NULL) printf("Out of Space!!!");
            else H->TheLists[i]->next=NULL;
        }
        return H;
    }
    
    int Hash(int key,int size)
    {
        return key%size;
    }
    Position Find(int key,HashTable H)
    {
        Position P;
        List L;
        L=H->TheLists[Hash(key,H->TableSize)];
        P=L->next;
        while(P!=NULL&&P->data!=key)
        {
            P=P->next;
        }
        return P;
    }
    void Insert(int key,HashTable H)
    {
        Position Pos,Cell;
        List L;
        Pos=Find(key,H);
        if(Pos==NULL)
        {
            Cell=(List)malloc(sizeof(struct Node));
            if(Cell==NULL) printf("Out of Space!!!");
            else
            {
                L=H->TheLists[Hash(key,H->TableSize)];
                Cell->next=L->next;
                Cell->data=key;
                L->next=Cell; 
            }
        } 
    } 
    void Print(HashTable H)
    {
        Position P,tmp;
        for(int i=0;i<H->TableSize;i++)
        {
            P=H->TheLists[i]->next;
            while(P!=NULL)
            {
                printf("%d ",P->data);
                P=P->next;
            }
            printf("
    ");
        }
    }
    int main(void)
    {
        HashTable H;
        int n,i,x;
        cin>>n;
        H=Init(n);
        for(i=0;i<n;i++)
        {
            cin>>x;
            Insert(x,H);
        }
        Print(H);
        return 0;
    }
    View Code

    (二)开放定址法

    1、相比于分离链接法的优点:不用指针,提高算法运行速度。

    2、原理:如果有冲突发生,尝试选择另外的单元,直到找到空单元为止。

    H(X)=(Hash(X)+F(i)) mod Size,并且F(0) = 0;

    3、注意:无法删除,要用懒惰删除。

    3、线性探测法

    (1)散列函数:F(i)=i;

    (2)缺点:如果有多于一半多元素被填满后就不是个好办法,会产生一次聚集。

    4、平方探测法

    (1)散列函数:F(i)=i^2;

    (2)代码中使用快速平方法F(i)=F(i-1)+2*i-1;

    优点:解决线性探测法中的一次聚集问题。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    using namespace std;
    const int MAXSIZE = 12000;
    typedef unsigned int Index;
    typedef Index Position;
    enum Kind{
        Legitimate,Empty,Deleted
    };
    
    struct Node{
        int data;
        enum Kind Info;
    }; 
    typedef struct Node Cell;
    
    struct HNode{
        int TableSize;
        Cell *TheCells;
    };
    typedef struct HNode* HashTable;
    bool IsPrim(int x)
    {
        for(int i=2;i*i<=x;i++)
        if(x%i==0) return false;
        return true;
    }
    int NextPrim(int x)
    {
        while(!IsPrim(x)) x++;
        return x; 
    }
    HashTable Init(int size)
    {
        HashTable H;
        int i;
        if(size>MAXSIZE)
        {
            printf("Too small
    ");
            return NULL;
        }
        H=(HashTable)malloc(sizeof(struct HNode));
        if(H==NULL) printf("Out of Space");
        H->TableSize=NextPrim(size);
        
        H->TheCells=(Cell*)malloc(sizeof(Cell)*H->TableSize);
        if(H->TheCells==NULL) printf("Out of Space");
        for(i=0;i<H->TableSize;i++)
        H->TheCells[i].Info=Empty;
        return H;
    }
    Index Hash(int x,int size)
    {
        return x%size;
    }
    Position Find(int key,HashTable H)
    {
        Position Pos;
        int num=0;
        Pos=Hash(key,H->TableSize);
        while(H->TheCells[Pos].Info!=Empty&&H->TheCells[Pos].data!=key)
        {
            Pos+=2*++num-1;
            if(Pos>=H->TableSize) Pos-=H->TableSize;
        }
        return Pos;
    }
    void Insert(int key,HashTable H)
    {
        Position Pos=Find(key,H);
        if(H->TheCells[Pos].Info!=Legitimate)
        {
            H->TheCells[Pos].Info=Legitimate;
            H->TheCells[Pos].data=key;
        }
    }
    void Print(HashTable H)
    {
        for(int i=0;i<H->TableSize;i++)
        {
            if(H->TheCells[i].Info==Legitimate)
            printf("%d ",H->TheCells[i].data);
        }
        printf("
    ");
    }
    int main(void)
    {
        int n,i,x;
        HashTable H;
        cin>>n;
        H=Init(n);
        for(i=1;i<=n;i++)
        {
            cin>>x;
            Insert(x,H);
        }
        Print(H);
        return 0;
    }
    View Code

    5、双散列

    (1)散列函数:F(i)=i*Hash(X);

    (2)Hash(X)的选取很重要。

    6、再散列

    如果插入后表的一部分是满的,就再建立一个大约两倍的表(原表和新表的大小都是素数)。

  • 相关阅读:
    对于Python中self的看法
    SpringBoot整合MyBatis-Plus快速开始
    Hive原理--体系结构
    Docker Compose + Traefik v2 快速安装, 自动申请SSL证书 http转https 初次尝试
    记录:更新VS2019后单元测试运行卡住无法运行测试的问题。
    黑帽来源页劫持代码以及如何防范
    OFFICE 2010 每次打开提示安装的问题
    Mssql 查询某记录前后N条
    验证邮箱正则表达式,包含二级域名邮箱,手机号正则表达式支持170号段
    删除TFS上的团队项目
  • 原文地址:https://www.cnblogs.com/2018zxy/p/10207518.html
Copyright © 2020-2023  润新知