这里写目录标题
散列表
散列表用于解决查找问题,已知查找方法有
- 顺序查找
- 二分查找
- 二叉搜索树(平衡二叉树)
当我们面对庞大的信息库的时候,查找就会消耗大量的时间,面对动态的查找情况,不断有数据插入和删除,所以查找就显得不太容易。散列查找就是解决这种问题的,可以通过元素快速知道位置所在。
散列查找的任务:1)计算函数,把对象映射成一个序号;2)解决冲突,就是当有两个对象映射到一个位置的时候怎么解决。
散列表的基本思想
以关键字key为自变量,通过一个确定的函数h(散列函数),计算出对应的函数值h(key),作为数据对象的储存地址
散列表抽象数据类型
数字关键字散列函数的构造
直接定址法
除留余数法
数字分析法
折叠法
平方取中法
字符关键字散列函数的构造
- 移位法伪代码
Index Hash(const char *Key,int tableSize)
{
unsigned int h=0;
while(*Key!='\0')
h=(h<<5)+*Key++;
return h % TableSize//tableSize是散列表的长度
}
冲突处理方法
常用的处理冲突的思路:开放地址法和链地址法。
- 链地址法意思是每个地址储存一个指向链表的指针,当发生冲突的时候就接着往链条后边存。
- 开放地址法意思就是不断试探新的地址,根据试探新地址方式的不同又分为开放地址法,平方地址法和双散列法。
开放地址法
若发生第i次冲突,试探的下一个地址增加di。
线性探测法
散列表查找性能分析
平方探测
线性探索时散列表中只要有空位,就可以找到
二次探测的时候,可能会忽略空位
散列表操作集伪代码
建立空的散列表
HashTable initializeTable(int TableSize)
{
HashTable H;
int i;
if (TableSize < 10)
{
printf("散列表太小");
return NULL;
}
H = (HashTable)malloc(sizeof(struct HashTbl));
if (H == NULL)
{
printf("空间溢出");
return NULL;
}
H->TableSize = TableSize;
H->TheCells = (struct Cell*)malloc(sizeof(struct Cell) * H->TableSize);
if (H->TheCells == NULL)
printf("空间溢出");
for (int i = 0; i < H->TableSize; i++)
H->TheCells[i].Info = 0;
return H;
}
查找某元素在散列表中的值
int Find(int Key, HashTable H)
{
int CNum = 0;
int CurrentPos, NewPos;
NewPos = CurrentPos = Hash(Key, H->TableSize);
while (H->TheCells[NewPos].Info != 0&& H->TheCells[NewPos].ElementSize != Key)
{
if (++CNum % 2)
{
NewPos = CurrentPos + (CNum + 1) / 2 * (CNum + 1) / 2;
while (NewPos >= H->TableSize)
{
NewPos -= H->TableSize;
}
}
else
{
NewPos = CurrentPos - (CNum + 1) / 2 * (CNum + 1) / 2;
while (NewPos <0)
{
NewPos += H->TableSize;
}
}
}
return NewPos;
}
插入
void Insert(int Key, HashTable H)
{
int Pos;
Pos = Find(Key, H);
if (H->TheCells[Pos].Info != 1)
{
H->TheCells[Pos].Info = 1;
H->TheCells[Pos].ElementSize = Key;
}
}
散列表结构类型
struct Cell
{
int ElementSize;
int Info;
}arr[10];
结构体数组,数组元素都是结构体;
struct HashTbl
{
int TableSize;
struct Cell* TheCells;
}H;