第十章 基本数据结构
栈:可由数组表示
队列:可由数组表示
指针和对象:可由多数组表示。可用栈表示free list
有根数:
二叉树:左右孩子
分支无限制:左孩子右兄弟表示法
第十一章 散列表
数组:为每个元素保留一个位置
散列表:用于实际存储关键字比全部可能关键字少很多时,比如字典操作
解决散列冲突:链接法,开放寻址法
11.2 散列表
用链表法,在简单均匀散列的假设下,一次成功或不成功的查找所需要的平均时间为Θ(1+α),α为load factor。
11.3 散列函数
好的散列函数应(近似地)满足简单均匀假设:每个关键字都被等肯能地散列到m个槽位中的任何一个,并与其它关键字已散列到哪个槽位无关。
利用关键字分布的有用信息。如“pt”,“pts”不冲突
一种好的方法导出的散列值,在某种程度上应独立于数据可能存在的任何模式。如除法散列
散列函数的某些应用可能会要求比简单均匀散列更强的性质,如全域散列可使相似关键字有截然不同散列值。
全域散列函数:一组函数H称为全域的,如果对每一对不同的关键字k,l属于U,满足h(k)=h(l)的散列函数个数至多为[H]/m,m为槽位数。
如:p为足够大素数,使得每一关键字k都在[0,p-1],Zp={0,1,...,p-1},Zp*={1,2,...,p-1},
hab(k)=((ak+b)mod p)mod m
Hpm={hab: a属于Zp*,b属于Zp}
11.4 开放寻址法
所有元素都在散列表中,装载因子不超过1。探查顺序是0~m-1的一个排列,依赖于h(k,i),i为探查号。不使用指针,节省空间。
但有关键字删除时即使设置标志deleted,查找时间也不再依赖于a。这种情况更适合用链接法来解决冲突。
均匀散列:每个关键字的探查序列等可能地为0~m-1的m!种排列的任一种。难实现,只能近似(如双重散列)。
三种技术:线性探查,二次探查,双重探查。
线性探查:h(k,i)=(h'(k)+i)mod m。连续被占用时间越多,查找时间越长。
二次探查:h(k,i)=(h'(k)+c1i+c2i2)mod m。初始位置决定探查序列。
双重探查:h(k,i)=(h1(k)+ih2(k))mod m。
11.5 完全散列
散列有良好的平均性能。
特别地,当关键值是静态(存入后不变,如程序的保留字)时,完全散列能提供出色的最坏情况性能O(1)。
通过两级的散列来设计完全散列方案,在每级上都使用全域散列。二次散列表不用链表,通过精心选择hi,确保在第二级上不发生冲突。
定理11.9: 如果从一个全域散列函数类中随机算出散列函数h,将n个关键字存储在一个大小为m=n2的散列表中,那么表中出现冲突的概率小于1/2.
定理11.10: 如果从一个全域散列函数类中随机算出散列函数h,用它将n个关键字存储在一个大小为m=n的散列表中,则有
E[Σnj2]<2n nj为散列到槽j的关键值数。
推论:如果二次散列大小为mj=nj2,则存储所有二次散列表所需的存储总量的期望值小于2n。
推论2:存储所有二次散列表的存储总量等于或大于4n的概率小于1/2。