散列函数:一个把查找表中的关键字映射成该关键字对应的地址的函数,记为Hash(key)=Addr。
散列函数可能会把两个或以上的不同关键字映射到同一地址,称这种情况为”冲突“,这些发生碰撞的不同关键字称为同义词。
一方面,设计好的散列函数应尽量减少这样的冲突;另一方面,由于这样的冲突是不可避免的,所以还要设计好处理冲突的方法。
散列表:是根据关键字而直接进行访问的数据结构。也就是说,散列表建立了关键字和存储地址之间的一种直接映射关系。
以下简单示例通过除留余数法的方式构造散列函数,通过开放地址法的方式处理冲突。
//
// Created by Administrator on 2018/7/12.
//
#include "stdio.h"
#include "stdlib.h"
#define HASHSIZE 10
#define NULLKEY NULL
typedef struct {
int *elem; //通过指针的方式代替数组
int size; //当前容量
} HashTable;
/**
* 初始化创建hashtable
* @return
*/
HashTable createHashTable() {
HashTable hashTable;
hashTable.size = 0;
hashTable.elem = (int *) malloc(HASHSIZE * sizeof(int));
for (int i = 0; i < HASHSIZE; ++i) {
//初始化数据
hashTable.elem[i] = NULLKEY;
}
return hashTable;
}
/**
* 通过除留余数法构造hash函数
* @param key 关键字key
* @return
*/
int hash(int key) {
int hash = key % HASHSIZE;
return hash;
}
/**
* 向hashtable中插入元素
* @param hashTable
* @param key
* @return
*/
HashTable put(HashTable hashTable, int key) {
int addr = hash(key);
while (hashTable.elem[addr] != NULLKEY) {
//该位置已存在元素,使用简单的开放地址法处理冲突
addr = (hash(key) + 1) % HASHSIZE;
}
hashTable.elem[addr] = key;
hashTable.size++;
return hashTable;
}
/**
* 查找元素在hashtable中的位置
* @param hashTable
* @param key
* @return
*/
int search(HashTable hashTable, int key) {
int addr = hash(key);
int elem = hashTable.elem[addr];
while (elem != key) {
addr = (addr + 1) % HASHSIZE;
elem = hashTable.elem[addr];
if (elem == NULLKEY || addr == hash(key)) {
//遍历完成 仍然没有找到
return -1;
}
}
return addr;
}
int main() {
HashTable hashTable = createHashTable();
for (int i = 5; i < 15; i++) {
hashTable = put(hashTable, i);
}
int key = 14;
int addr = search(hashTable, key);
printf("查找到key=%d的元素,地址=%d", key, addr);
printf("\nhashtable 当前容量=%d", hashTable.size);
}