数据结构之散列

    散列是一种以常数平均时间执行插入、删除和查找的技术。理想的散列表数据结构只不过是一个包含有关键字的具有固定大小
的数组。典型情况下,一个关键字就是一个带有相关值得字符串。我们把表的大小记作tableSize。每个关键字经过散列函数都会被映射到0到tableSize-1范围内。通常是保证表的大小为素数。如果不同的关键字映射到了相同的值,这时候就会产生冲突。
解决冲突的方法有分离链接法和开放定址法。


 分离链接法 : 将散列到同一个值得所有元素保留到同一个表中,通过链表实现(如下图)

                                      

 开放定址法 : 发生冲突后,就会尝试选择另外的单元,直到找到空单元为止。一般来说,装填因子应小于0.5(表中元素个数与表大小的比值)。对于找另外单元的方法通常是线性探测法、平方探测法、双散列

下面是散列的分离链接法实现

头文件hashtable.h

#ifndef HASHTABLE_H_
#define HASHTABLE_H_

struct Node;
struct HashTable;
typedef struct Node *ptrToNode;
typedef ptrToNode *List;
typedef struct HashTable *ptrToHashTable;
typedef int ElementType;

//创建散列表
ptrToHashTable createHashTable(int tableSize);
//散列函数
int hash(ElementType key,int tableSize);
//插入数据
void insert(ptrToHashTable H,ElementType e);
//查找数据
ptrToNode find(ptrToHashTable H,ElementType key);
//输出散列表
void printHashTable(ptrToHashTable H);
//销毁散列表
void destory(ptrToHashTable &H);

#endif /* HASHTABLE_H_ */

具体实现

#include <stdio.h>
#include <stdlib.h>
#include "hashtable.h"

struct Node {
	ElementType data;
	ptrToNode next;
};

struct HashTable {
	int tableSize; //表大小
	List tableList; //表头指针列表
};

/*
 * 创建散列表表头列表,传入表的大小
 * 解决冲突方法:分离链接法
 */
ptrToHashTable createHashTable(int tableSize) {
	ptrToHashTable H = (ptrToHashTable) malloc(sizeof(struct HashTable));
	if (H == NULL) {
		printf("create fail\n");
		return NULL;
	}

	H->tableSize = tableSize;
	H->tableList = (List) malloc(sizeof(ptrToNode) * tableSize);

	if(H->tableList == NULL){
		printf("create fail\n");
		free(H);
		return NULL;
	}

	//创建表头
	ptrToNode nodeList = (ptrToNode) malloc(sizeof(struct Node) * tableSize);
	for (int i = 0; i < tableSize; i++) {
		H->tableList[i] = &nodeList[i];
		H->tableList[i]->next = NULL;
	}
	return H;
}

/**
 * 插入元素
 */
void insert(ptrToHashTable H, ElementType e) {
	//查看元素是否已在表中
	ptrToNode ptr = find(H, e);

	if (ptr == NULL) {
		int index = hash(e, H->tableSize);
		ptr = (ptrToNode) malloc(sizeof(struct Node));
		if(ptr == NULL){
			printf("malloc fail\n");
		}
		ptr->data = e;
		ptr->next = (H->tableList[index])->next;
		H->tableList[index]->next = ptr;
	}
}

/**
 * 查找关键字,如果已在表中就返回它所在的节点指针,否则返回NULL
 */
ptrToNode find(ptrToHashTable H, ElementType key) {
	int index = hash(key, H->tableSize);
	ptrToNode ptr = H->tableList[index]->next;
	while (ptr != NULL && ptr->data != key) {
		ptr = ptr->next;
	}
	return ptr;
}

/**
 * 输出散列表的内容
 */
void printHashTable(ptrToHashTable H) {
	ptrToNode ptr;
	for (int i = 0; i < H->tableSize; i++) {
		ptr = H->tableList[i]->next;

		while (ptr != NULL) {
			printf("%d ", ptr->data);
			ptr = ptr->next;
		}
		printf("\n");
	}
}

/**
 * 求关键字散列值
 */
int hash(ElementType key, int tableSize) {
	return key % tableSize;
}

/**
 * 销毁散列表
 */
void destory(ptrToHashTable &H) {
	if(H == NULL)
		return;
	ptrToNode ptr,temp;
	for (int i = 0; i < H->tableSize; i++) {
		ptr = H->tableList[i]->next;
		while (ptr != NULL) {
			temp = ptr;
			ptr = ptr->next;
			free(temp);
		}
	}
	free(H->tableList);
	free(H);
	H = NULL;
}

测试

#include <stdio.h>
#include "hashtable.h"

int main() {
	ptrToHashTable H = createHashTable(7); //创建散列表

	//插入数据
	insert(H, 2);
	insert(H, 3);
	insert(H, 7);
	insert(H, 9);
	insert(H, 25);
	insert(H, 30);
	insert(H, 8);
	insert(H, 4);
	insert(H, 12);
	insert(H, 6);
	insert(H, 17);
	insert(H, 19);
	insert(H, 99);
	insert(H, 19);
	insert(H, 99);

	//输出
	printHashTable(H);
	destory(H);//销毁
	return 0;
}




猜你喜欢

转载自blog.csdn.net/jygqm/article/details/80740359