许多应用都需要一种动态集合结构,它至少要支持INSERT,SEARCH,DELETE字典操作,例如,用于程序语言编译的编译器维护了一个符号表,其中元素的关键字为任意字符串,它与程序中的标识符相对应。散列表(hash table)是实现字典操作的一种有效的数据结构。尽管最坏的情况下,散列表中查找一个元素的时间与链表中查找的时间相同,达到了。然而在实际应用中,散列查找的性能是极好的。在一些合理的假设中,在散列表中查找一个元素的平均时间是O(1);
一,直接寻址法
当存储的数据的关键字的范围比较小时,直接寻址是一种简单而有效的技术。假设某应用要用到一个动态集合,其中每个元素都是取自于全域U = {0,1,2...,m-1}中的关键字,这里m不是一个很大的数。另外,假设没有冲突(没有两个元素具有相同的关键字)。
为表示动态集合,我们用一个数组,或称为直接寻址表(direct-address table),记为T[0...m-1]
其中每个位置,或称为槽(slot),对应全域U中的一个关键字。槽k指向集合中一个关键字为k的元素,如果给集合中没有关键字为k的元素,则T[k]为空。
如图:
测试代码:
#include<iostream>
using namespace std;
typedef char DataType;
typedef struct DATA
{
int key;
DataType data;
}DATA;
DataType DIRECT_ADDRESS_SEARCH(DATA* T[], int k) //搜索
{
return T[k]->data;
}
void DIRECT_ADDRESS_INSERT(DATA* T[], DATA& x) //插入数据
{
T[x.key] = &x;
}
void DIRECT_ADDRESS_DELETE(DATA* T[], DATA& x) //删除数据
{
T[x.key] = NULL;
}
int main()
{
DATA a1, a2, a3;
a1.key = 3;
a1.data = 'A';
a2.key = 4;
a2.data = 'B';
a3.key = 5;
a3.data = 'C';
DATA* T[9];
for (int i = 0; i < 9; ++i)
{
T[i] = NULL;
}
DIRECT_ADDRESS_INSERT(T, a1);
DIRECT_ADDRESS_INSERT(T, a2);
DIRECT_ADDRESS_INSERT(T, a3);
//数据存到寻址表之后再需要寻找数据可直接通过关键字查找
for (int i = 0; i < 9; ++i)
{
printf("T[%d]->", i);
if(T[i])
printf("[%d][%c]\n", T[i]->key, T[i]->data);
else
printf("NULL\n");
}
printf("T[3]=%c\n", DIRECT_ADDRESS_SEARCH(T, 3));
printf("T[4]=%c\n", DIRECT_ADDRESS_SEARCH(T, 4));
printf("T[5]=%c\n", DIRECT_ADDRESS_SEARCH(T, 5));
DIRECT_ADDRESS_DELETE(T, a1);
for (int i = 0; i < 9; ++i)
{
printf("T[%d]->", i);
if (T[i])
printf("[%d][%c]\n", T[i]->key, T[i]->data);
else
printf("NULL\n");
}
}
输出:
T[0]->NULL
T[1]->NULL
T[2]->NULL
T[3]->[3][A]
T[4]->[4][B]
T[5]->[5][C]
T[6]->NULL
T[7]->NULL
T[8]->NULL
T[3]=A
T[4]=B
T[5]=C
T