哈希表3- 数据结构(C语言)

重建哈希表

  1. 如何重建哈希表。还当插入关键字时,如果发生的冲突次数 达到哈希表长度的一半,表明当前哈希表已经发生了 “堆聚” 现象,为了减少这种现象,提高查找效率,我们需要重建哈希表。
    重建哈希表的原理很简单,把原来数组里已有的关键字取出来临时存储,然后将原来数组扩大,再把关键字–插回去就可以了。
    接下来,我们就来实现哈希表的重建函数recreate. 首先我们先把定义写好,recreate 没有返回值,参数只有一个HashTable 类型的指针h.
  2. 我们先来完成第一步,将原来数组里的元素都取出来,存到临时空间里。 首先我们定义一个char 类型的二维指针变量 temp_elem, 然后我们给temp_elem 申请h->size和个 char * 类型的存储空间。这里我们分成两行来写,借助malloc 来分配内存。
  3. 接下来我们用for 循环,用变量 i 从 0 循环到不小于 h->size 时退出。如果原来哈希数组当前位置不为空,则给temp_elem[i] 分配 strlen(h->elem[i]) + 1大小的内存空间。然后将原哈希表里的关键字取出,存放在临时数组temp_elem[i] 里。
    for 循环 记得写上花括号,字符串拷贝用strcpy 函数。
  4. 如果哈希表当前位置没有元素,则将临时哈希表的当前第i 个位置也置为空。这里我们直接用else 语句中实现它的逻辑就好了。
  5. 接下来我们先释放哈希表 h 原来 elem 的存储空间。首先写一个for 循环,用int 类型的变量 i 从 0 循环到不小于 h->size 时退出。for 循环内完成对每个不为空的字符串 elem[i] 进行内存空间回收。
    在for 循环后面再完成对二维指针变量elem的空间回收,指针回收用free.
  6. 接下来 我们要扩大哈希表了, 在这之前我们需要定义一个 int 类型的指针变量copy_size, 存储原来的哈希表h 的长度 size , 因为后面我们还会用到size . 然后,我们把size 扩大一倍,做为新的哈希表长度。最后,我们给新的elem 申请 size 个 char * 类型的存储空间。
  7. 哈希数组扩大后,我们要使用for 循环把哈希表h 上的每个字符串 elem[i] 置为空。
  8. 接下来我们把原来哈希表里的关键字-- 插入到新的哈希表里。这里我们先写好for 循环,用变量 i 从 0 循环到不小于 copy_size 时退出来完成循环。
    注意此时不能用size ,因为size 现在存的是新的哈希表长度,copy_size 存的才是原来的哈希表长度。
  9. 那么现在我们在for 循环里, 把关键字插入到新的哈希表里。 因为不是把哈希表里的每一位都插入,而是只有存储了关键字的元素才需要插入,所以我们还先要判断当前位置上是否为空,如果不为空则调用 insert 函数将该位置上的关键字插入到哈希表里。
  10. 现在只剩下最后一步了,在recreate 最后将temp_elem 指向的空间删除,避免内存泄露。
    首先写一个for 循环,用int 类型的变量 i 从 0 循环到小于 copy_size. for 循环内判断当前位置是否为空,不为空则把temp_elem[i] 的空间回收。在for 循环后面再完成对二维指针变量temp_elem 的空间回收。指针回收用free.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct HashTable {
    char **elem;
    int size;
} HashTable;

void init(HashTable *h);
int hash(HashTable *h, char value[]);
int search(HashTable *h, char value[], int *pos, int *times);
int insert(HashTable *h, char value[]);
void recreate(HashTable *h);

void init(HashTable *h) {
    h->size = 2000;
    h->elem = (char **)malloc(sizeof(char *) * h->size);
    for (int i = 0; i < h->size; i++) {
        h->elem[i] = NULL;
    }
}

int hash(HashTable *h, char value[]) {
    int code = 0;
    for (size_t i = 0; i < strlen(value); i++) {
        code = (code * 256 + value[i] + 128) % h->size;
    }
    return code;
}

int search(HashTable *h, char value[], int *pos, int *times) {
    *pos = hash(h, value);
    *times = 0;
    while (h->elem[*pos] != NULL && strcmp(h->elem[*pos], value) != 0) {
        (*times)++;
        if (*times < h->size) {
            *pos = (*pos + 1) % h->size;
        } else {
            return 0;
        }
    }
    if (h->elem[*pos] != NULL && strcmp(h->elem[*pos], value) == 0) {
        return 1;
    } else {
        return 0;
    }
}

int insert(HashTable *h, char value[]) {
    int pos, times;
    if (search(h, value, &pos, &times)) {
        return 2;
    } else if (times < h->size / 2) {
        h->elem[pos] = (char *)malloc(strlen(value) + 1);
        strcpy(h->elem[pos], value);
        return 1;
    } else {
        recreate(h);
        insert(h, value);
        return 0;
    }
}

// 请在下面实现哈希表重建函数 recreate
void recreate(HashTable *h) {
    char **temp_elem;
    temp_elem = (char **)malloc(sizeof(char *) * h->size);
    // for 循环,用变量 i  从 0 循环不小于 h->size 时退出。如果原来哈希数组 当前位置不为空,
    //   则给 temp_elem[i] 分配 strlen(h->elem[i]) + 1 大小的内存空间 
    
    for(int i = 0; i<h->size; i ++) {
       if(h->elem[i] != NULL) {
           temp_elem[i] =  (char *)malloc(strlen(h->elem[i]) + 1);
           strcpy(temp_elem[i], h->elem[i]);
       } else {
           // 临时哈希表当前第 i 个位置 置为空
           temp_elem[i] = NULL;
       }
    }
    
    for(int i = 0; i < h -> size; i++) {
        if(h->elem[i] != NULL){
            free(h->elem[i]);
        }
    }
    free(h->elem);
    
    int copy_size = h->size;
    h->size = h->size * 2;
    h->elem = (char **)malloc(sizeof(char *) * h->size);
    for(int i =0; i < h->size; i++) {
        h->elem[i] = NULL;
    }
    
    for(int i = 0; i < copy_size; i++) {
        if(temp_elem[i] != NULL){
            insert(h,temp_elem[i]);
        }
    }
    
    for(int i = 0; i < copy_size; i++) {
        if(temp_elem[i] != NULL) {
            free(temp_elem[i]);
        }
    }
    free(temp_elem);
}

void clear(HashTable *h) {
    for (int i = 0; i < h->size; ++i) {
        if (h->elem[i] != NULL) {
            free(h->elem[i]);
        }
    }
    free(h->elem);
    free(h);
}

int main() {
    HashTable *hashtable = (HashTable*)malloc(sizeof(HashTable));
    init(hashtable);
    char buffer[1000];
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%s", buffer);
        int ans = insert(hashtable, buffer);
        if (ans == 0) {
            printf("recreate while insert!\n");
        } else if (ans == 1) {
            printf("insert success!\n");
        } else if (ans == 2) {
            printf("It already exists!\n");
        }
    }
    int temp_pos, temp_times;
    scanf("%s", buffer);
    if (search(hashtable, buffer, &temp_pos, &temp_times)) {
        printf("search success!\n");
    } else {
        printf("search failed!\n");
    }
    clear(hashtable);
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值