Hash Table

散列用来以常数时间实现 Insert、Find 和 Delete 操作。

With direct addressing, an element with key k is stored in slot k.(相当于数组)
With hashing, this element is stored in slot h(k); that is, we use a hash function h to compute the slot from the key k.

h(k) 的范围远小于 k,所以必定会产生冲突(Collision)。
哈希函数表大小一般选择素数,可以使得均匀分布,缓解冲突。(为什么素数可以做到均匀分布?)

解决冲突方法一:链表数组实现,觉得代码很漂亮^_^
typedef int ElementType;
typedef struct ListNode *Position;

struct ListNode
{
	ElementType Element;
	Position	Next;
};

typedef Position List;

struct HashTbl
{
	int TableSize;
	List *TheLists; // an array of lists
};

typedef struct HashTbl *HashTable;


HashTable InitializeTable(int TableSize)
{
	HashTable H;
	int i;
	
	H = (HashTbl *)malloc(sizeof(struct HashTbl));
	if (H == NULL)
		Error("Out of space!!!");

	H->TableSize = NextPrime(TableSize);

	H->TheLists = (List *)malloc(sizeof(List) * H->TableSize);
	if (H->TheLists == NULL)
		Error("Out of space!!!");

	/* Allocate list headers */
	for (i = 0; i < H->TableSize; i++)
	{
		H->TheLists[i] = (ListNode *)malloc(sizeof(struct ListNode));
		if (H->TheLists[i] == NULL)
			Error("Out of space!!!");
		else
			H->TheLists[i]->Next = NULL;
	}

	return H;
}

int Hash(ElementType Key, int TableSize)
{
	return Key%TableSize;
}

Position Find(ElementType Key, HashTable H)
{
	List L = H->TheLists[Hash(Key, H->TableSize)];
	Position P = L->Next;

	while (P != NULL && P->Element != Key)
		P = P->Next;

	return P;
}

void Insert(ElementType Key, HashTable H)
{
	Position Pos, NewCell;
	List L;

	Pos = Find(Key, H);

	if (Pos == NULL)
	{
		NewCell = (ListNode *)malloc(sizeof(struct ListNode));
		if (NewCell == NULL) {
			Error("Out of space!!!");
		} else {
			L = H->TheLists[Hash(Key, H->TableSize)];
			NewCell->Next = L->Next;
			NewCell->Element = Key;
			L->Next = NewCell;
		}
	}
}

void DestroyTable(HashTable H)
{
	int i;

	for (i = 0; i < H->TableSize; i++)
	{
		Position P = H->TheLists[i];
		Position Tmp;

		while (P != NULL) {
			Tmp = P->Next;
			free(P);
			P = Tmp;
		}
	}

	free(H->TheLists);
	free(H);
}

解决冲突方法二: Open addressing,数组实现
每个位置需要附加一个属性,表示这个位置 已存、空的或已删的
1. 线性探测法:往后面一个一个地找。
2. 平方探测法:往后面跳着找。
只能懒惰删除,不能真删。即标记已删。
再散列:表的大小不够时,建立另外一个大约两倍大小的新表,扫描原表,一个一个的插入到新表中。

来自《数据结构与算法分析》

你可能感兴趣的:(数据结构,算法)