散列表(四):衝突處理的方法之開地址法(二次探測再雜湊的實現)
阿新 • • 發佈:2018-12-25
#include "hash.h"
#include "common.h"
#include <assert.h>
typedef enum entry_status
{
EMPTY,
ACTIVE,
DELETED
} entry_status_t;
typedef struct hash_node
{
enum entry_status status;
void *key;
unsigned int key_size; //在拷貝進新的雜湊表時有用
void *value;
unsigned int value_size; //在拷貝進新的雜湊表時有用
} hash_node_t;
struct hash
{
unsigned int buckets;
unsigned int size; //累加,如果size > buckets / 2 ,則需要開裂建立新表
hashfunc_t hash_func;
hash_node_t *nodes;
};
unsigned int next_prime(unsigned int n);
int is_prime(unsigned int n);
unsigned int hash_get_bucket(hash_t *hash, void *key);
hash_node_t *hash_get_node_by_key(hash_t *hash, void *key, unsigned int key_size);
hash_t *hash_alloc(unsigned int buckets, hashfunc_t hash_func)
{
hash_t *hash = (hash_t *)malloc(sizeof(hash_t));
//assert(hash != NULL);
hash->buckets = buckets;
hash->hash_func = hash_func;
int size = buckets * sizeof(hash_node_t);
hash->nodes = (hash_node_t *)malloc(size);
memset(hash->nodes, 0 , size);
printf("The hash table has allocate.\n");
return hash;
}
void hash_free(hash_t *hash)
{
unsigned int buckets = hash->buckets;
int i;
for (i = 0; i < buckets; i++)
{
if (hash->nodes[i].status != EMPTY)
{
free(hash->nodes[i].key);
free(hash->nodes[i].value);
}
}
free(hash->nodes);
printf("The hash table has free.\n");
}
void *hash_lookup_entry(hash_t *hash, void *key, unsigned int key_size)
{
hash_node_t *node = hash_get_node_by_key(hash, key, key_size);
if (node == NULL)
{
return NULL;
}
return node->value;
}
void hash_add_entry(hash_t *hash, void *key, unsigned int key_size,
void *value, unsigned int value_size)
{
if (hash_lookup_entry(hash, key, key_size))
{
fprintf(stderr, "duplicate hash key\n");
return;
}
unsigned int bucket = hash_get_bucket(hash, key);
unsigned int i = bucket;
unsigned int j = i;
int k = 1;
int odd = 1;
while (hash->nodes[i].status == ACTIVE)
{
if (odd)
{
i = j + k * k;
odd = 0;
// i % hash->buckets;
while (i >= hash->buckets)
{
i -= hash->buckets;
}
}
else
{
i = j - k * k;
odd = 1;
while (i < 0)
{
i += hash->buckets;
}
++k;
}
}
hash->nodes[i].status = ACTIVE;
if (hash->nodes[i].key) ////釋放原來被邏輯刪除的項的記憶體
{
free(hash->nodes[i].key);
}
hash->nodes[i].key = malloc(key_size);
hash->nodes[i].key_size = key_size; //儲存key_size;
memcpy(hash->nodes[i].key, key, key_size);
if (hash->nodes[i].value) //釋放原來被邏輯刪除的項的記憶體
{
free(hash->nodes[i].value);
}
hash->nodes[i].value = malloc(value_size);
hash->nodes[i].value_size = value_size; //儲存value_size;
memcpy(hash->nodes[i].value, value, value_size);
if (++(hash->size) < hash->buckets / 2)
return;
//在搜尋時可以不考慮表裝滿的情況;
//但在插入時必須確保表的裝填因子不超過0.5。
//如果超出,必須將表長度擴充一倍,進行表的分裂。
unsigned int old_buckets = hash->buckets;
hash->buckets = next_prime(2 * old_buckets);
hash_node_t *p = hash->nodes;
unsigned int size;
hash->size = 0; //從0 開始計算
size = sizeof(hash_node_t) * hash->buckets;
hash->nodes = (hash_node_t *)malloc(size);
memset(hash->nodes, 0, size);
for (i = 0; i < old_buckets; i++)
{
if (p[i].status == ACTIVE)
{
hash_add_entry(hash, p[i].key, p[i].key_size, p[i].value, p[i].value_size);
}
}
for (i = 0; i < old_buckets; i++)
{
#include "common.h"
#include <assert.h>
typedef enum entry_status
{
EMPTY,
ACTIVE,
DELETED
} entry_status_t;
typedef struct hash_node
{
enum entry_status status;
void *key;
unsigned int key_size; //在拷貝進新的雜湊表時有用
void *value;
unsigned int value_size; //在拷貝進新的雜湊表時有用
struct hash
{
unsigned int buckets;
unsigned int size; //累加,如果size > buckets / 2 ,則需要開裂建立新表
hashfunc_t hash_func;
hash_node_t *nodes;
};
unsigned int next_prime(unsigned int n);
int is_prime(unsigned int n);
unsigned int hash_get_bucket(hash_t *hash, void *key);
hash_node_t *hash_get_node_by_key(hash_t *hash, void
hash_t *hash_alloc(unsigned int buckets, hashfunc_t hash_func)
{
hash_t *hash = (hash_t *)malloc(sizeof(hash_t));
//assert(hash != NULL);
hash->buckets = buckets;
hash->hash_func = hash_func;
int size = buckets * sizeof(hash_node_t);
hash->nodes = (hash_node_t *)malloc(size);
memset(hash->nodes, 0
printf("The hash table has allocate.\n");
return hash;
}
void hash_free(hash_t *hash)
{
unsigned int buckets = hash->buckets;
int i;
for (i = 0; i < buckets; i++)
{
if (hash->nodes[i].status != EMPTY)
{
free(hash->nodes[i].key);
free(hash->nodes[i].value);
}
}
free(hash->nodes);
printf("The hash table has free.\n");
}
void *hash_lookup_entry(hash_t *hash, void *key, unsigned int key_size)
{
hash_node_t *node = hash_get_node_by_key(hash, key, key_size);
if (node == NULL)
{
return NULL;
}
return node->value;
}
void hash_add_entry(hash_t *hash, void *key, unsigned int key_size,
void *value, unsigned int value_size)
{
if (hash_lookup_entry(hash, key, key_size))
{
fprintf(stderr, "duplicate hash key\n");
return;
}
unsigned int bucket = hash_get_bucket(hash, key);
unsigned int i = bucket;
unsigned int j = i;
int k = 1;
int odd = 1;
while (hash->nodes[i].status == ACTIVE)
{
if (odd)
{
i = j + k * k;
odd = 0;
// i % hash->buckets;
while (i >= hash->buckets)
{
i -= hash->buckets;
}
}
else
{
i = j - k * k;
odd = 1;
while (i < 0)
{
i += hash->buckets;
}
++k;
}
}
hash->nodes[i].status = ACTIVE;
if (hash->nodes[i].key) ////釋放原來被邏輯刪除的項的記憶體
{
free(hash->nodes[i].key);
}
hash->nodes[i].key = malloc(key_size);
hash->nodes[i].key_size = key_size; //儲存key_size;
memcpy(hash->nodes[i].key, key, key_size);
if (hash->nodes[i].value) //釋放原來被邏輯刪除的項的記憶體
{
free(hash->nodes[i].value);
}
hash->nodes[i].value = malloc(value_size);
hash->nodes[i].value_size = value_size; //儲存value_size;
memcpy(hash->nodes[i].value, value, value_size);
if (++(hash->size) < hash->buckets / 2)
return;
//在搜尋時可以不考慮表裝滿的情況;
//但在插入時必須確保表的裝填因子不超過0.5。
//如果超出,必須將表長度擴充一倍,進行表的分裂。
unsigned int old_buckets = hash->buckets;
hash->buckets = next_prime(2 * old_buckets);
hash_node_t *p = hash->nodes;
unsigned int size;
hash->size = 0; //從0 開始計算
size = sizeof(hash_node_t) * hash->buckets;
hash->nodes = (hash_node_t *)malloc(size);
memset(hash->nodes, 0, size);
for (i = 0; i < old_buckets; i++)
{
if (p[i].status == ACTIVE)
{
hash_add_entry(hash, p[i].key, p[i].key_size, p[i].value, p[i].value_size);
}
}
for (i = 0; i < old_buckets; i++)
{