数据结构之哈希表

       之前一直采用链表的方式存储数据,但是在实际应用中发现若链表长度太长且要经常查找数据时程序反应会比较慢,这是由于链表查找效率比较低,后来发现一种比较高效的链表查找方式——哈希表。哈希表为可通过关键字查找数据的数组,数据(关键字k)可通过某种关系(映射函数,也叫散列表,例如:y = f(k))存储在数组中,我们根据关键字就可在数组中查找到数据。若对于不同的关键字可得到到相同的值即k1!=k2, f(k1)==f(k2)成为碰撞或冲突。解决冲突的方法有很多如开放寻址法、再散列法、拉链法等,本文采用拉链法解决冲突。将某个一维数组全部元素都作为链表头,关键字通过映射(本文采用的是求余取模法,当然还有其他的方法可供选择)可得到数组中链表头部地址,创建一个节点,将该关键字存放到节点中,并将该节点插入到刚才找到的链表中去。

      节点数据结构:typedef struct node{
                   struct node *next;
                   TypeKey data;
            }Node;

    链表头数据结构:typedef struct hashtbale{
                  Node *head;
                 unsigned int size;    //哈希表中关键字个数
                 TypeKey  mode;    //哈希表长度,即模
          }Hash;

下面是对哈希表的操作:

(1)初始化

void InitHash(Hash *hash, unsigned int size)
{
    int i = 0;
    
    hash->size = 0;
    hash->mode = size;
    hash->head = (Node *)malloc(sizeof(Node)*size);
    
    if(hash->head == NULL)
        exit(0);
    
    for(i=0; i<hash->mode; i++){
        hash->head[i].data = i;
        hash->head[i].next = NULL;
    }
    
}

(2)插入关键字

void InsertKey(Hash *hash, TypeKey key)
{
    int add = key%hash->mode;
    
    Node *node = (Node *)malloc(sizeof(Node));
    
    node->next = hash->head[add].next;
    node->data = key;
    hash->head[add].next = node;
    hash->size ++;
}
(3)删除某个关键字

char DeletKey(Hash *hash, TypeKey key)
{
    int add = key%hash->mode;
    Node *p;
    Node *q;
    
    p = hash->head[add].next;
    if(p == NULL){
        printf("no such key");
        return -1;
    }
    
    if(p->data == key){
        hash->head[add].next = p->next;
        p->next = NULL;
        free(p);

       hash->size --;
        return 0;
    }
    
    q = p;
    p = p->next;
    
    while(p != NULL){
        if(p->data == key){
            q->next = p->next;
            p->next = NULL;
            free(p);

           hash->size --;
            return 0;
        }
        p = p->next;
        q = q->next;
    }
    
    printf("no such key \n");
    return -1;
    
}

(4)打印哈希表

void PrintHash(Hash hash)
{
    int i = 0;
    Node *p;
    Node *q;
    
    if(hash.head == NULL){
        printf("hashtable is null \n");
        return ;
    }
    
    for(i=0; i<hash.size; i++){
        printf("keyMode %d : \t",hash.head[i].data);
        p = hash.head[i].next;
        q = p;
        while(p != NULL){
            printf("%d ",p->data);
            p = p->next;
            if(hash.head+i == p){
                break;
            }
        }
        printf("\r\n");
    }
}

(5)测试函数

int main()
{
    int i = 0;
    Hash  hash;
    
    TypeKey  key[30] = {1, 52, 63, 96, 32 ,23, 64, 12, 210, 45, 57, 21, 36, 
                        55, 87, 123, 46, 62, 93, 82, 85, 86, 74, 73, 39, 38, 20, 
                        30, 43, 100};
    
    memset(&hash, 0, sizeof(hash));

   //创建一个哈希表,长度为10
    InitHash(&hash, 10);
    for(i=0; i<30; i++){
        InsertKey(&hash, key[i]);
    }
    InsertKey(&hash, 111);
 
    PrintHash(hash);

}

此外还有哈希表的清空与删除,可根据上述代码编写出来,不再罗列。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值