算法导论11.2-4未占用槽分配存储
2015-04-20 17:11
162 查看
一、题目
说明在散列表内部,如何通过将所有未占用的槽连接成一个自由链表,来分配和存储元素所占的存储空间。假定一个槽可以存储一个标志、一个元素、一个或两个指针。所有的字典和自由链表操作均应具有O(1)的期望运行时间。该自由链表需要是双向链表吗?或者单链表就足够了?
二、思路整理(参考官方答案)
每个槽slot有一个布尔值flag属性,表明是否已占用;
未占用slot:一个双向链表把空闲slot都连接起来,每个free slot有两个指针;
已占用slot:包含一个元素element和两个指针(参考答案是使用一个指针,这里为了方便)(可能nil),分别指向上一个和下一个散列到这个slot的元素,也就是是指向另一个slot。(因为所有element都存储在slot中)
一个slot定义如下:
插入操作:
1、如果元素x散列到一个空slot,将这个空slot从Free List移除,把x放到这个slot里,next指针指向nil,然后维护FreeList指针;
2、如果元素x散列到一个非空slot槽位j,该slot已存储元素y,分两种情况:
a、hash(y)=j:FreeList分配一个新slot存储x,将其插入y与y.next元素之间,即新slot指向y.next,y的指针指向新slot;
b、hash(y)≠j:FreeList分配新slot,用于存储y(包括元素、指针),指向旧slot的指针指向新slot,腾出的slot j存放x;
查找操作:
查找元素x,首先查找槽hash(x),如果不是,沿着链表指针一次查找。
删除操作:分三种情况,假设hash(x)=j,x散列到j
1、j.next=nil,即只有一个元素x散列到slot j,只需将j释放到自由表;
2、j.key=x,且j.next!=nil,x位于j槽,后面还有其他元素,把j.next移动到j,原j.next所占空间释放到自由表
3、j.key!=x且j.next!=nil,x位于j的next指针指向的后面的slot中,修改x前后元素指针,释放x所占slot.
//伪代码
//分配新slot
RemoveFromFreeSlot(s){//s为slot下标,代表槽对象
if(s.prev!=nil)
s.prev.next=s.next;
else free = s.next;
if(s.next!=nil)
s.next.prev=s.prev;
s.flag=1;
return s;
}
//释放slot到FreeList
FreeSlotToFreeList(s){
s.flag=0;
s.next=free;
free.prev=s;
free=s;
s.prev=nil;
}
Insertion(x){
j=hash(x);
if(j.flag==0)//插入一个空槽
RemoveFromFreeSlot(j);
j.next=nil;
j.prev=nil
j.key=x;
else
t=RemoveFromFreeSlot(free);//获取自由链表首位置
if(hash(j.key)==j)//2.a情况,把新元素放到t,修改前后元素指针
t.prev=j;t.key=x;t.next=j.next;
j.next=t;
else //2.b情况
t.key=j.key;t.prev=j.prev;t.next=j.next;//把j中原先的移到t,修改原先元素指针
if(t.next!=nil)t.next.prev=t;
if(t.prev!=nil)t.prev.next=t;
j.key=x;j.next=nil;j.prev=nil;//把x放到j
}
Search(x){
j=hash(x);
//x散列到槽为空,所以不存在x
//j存储的值不属于j,所以不存在x
if(j.flag==0||hash(j.key)!=j)return -1;
while(j!=nil&& j.key!=x)
j=j.next;
return j;
}
Delete(x){
j=hash(x);r=search(x);
if(r<0)return false;//不存在x
if(r==j && j.next==nil){
FreeSlotToFreeList(j);
}
else if(r==j && j.next!=nil){//把j下一位元素移到j,释放下一位元素位置
i=j.next;
j.key=i.key;
j.next=i.next;
if(i.next!=nil)i.next.prev=j;
FreeSlotToFreeList(i);
}
else
r.prev.next=r.next;
if(r.next!=nil)
r.next.prev=r.prev;
FreeSlotToFreeList(r);
}
说明在散列表内部,如何通过将所有未占用的槽连接成一个自由链表,来分配和存储元素所占的存储空间。假定一个槽可以存储一个标志、一个元素、一个或两个指针。所有的字典和自由链表操作均应具有O(1)的期望运行时间。该自由链表需要是双向链表吗?或者单链表就足够了?
二、思路整理(参考官方答案)
每个槽slot有一个布尔值flag属性,表明是否已占用;
未占用slot:一个双向链表把空闲slot都连接起来,每个free slot有两个指针;
已占用slot:包含一个元素element和两个指针(参考答案是使用一个指针,这里为了方便)(可能nil),分别指向上一个和下一个散列到这个slot的元素,也就是是指向另一个slot。(因为所有element都存储在slot中)
一个slot定义如下:
struct node(){ bool flag;//1为已占用,0未占用 int key;//未占用:没意义,-1;已占用:元素关键字 int prev;//未占用:上一个空槽;<span style="font-family: Arial, Helvetica, sans-serif;">已占用:上一个具有相同散列值的元素</span> int next;//未占用:下一个空slot ;已占用:下一个具有相同散列值的元素 }
插入操作:
1、如果元素x散列到一个空slot,将这个空slot从Free List移除,把x放到这个slot里,next指针指向nil,然后维护FreeList指针;
2、如果元素x散列到一个非空slot槽位j,该slot已存储元素y,分两种情况:
a、hash(y)=j:FreeList分配一个新slot存储x,将其插入y与y.next元素之间,即新slot指向y.next,y的指针指向新slot;
b、hash(y)≠j:FreeList分配新slot,用于存储y(包括元素、指针),指向旧slot的指针指向新slot,腾出的slot j存放x;
查找操作:
查找元素x,首先查找槽hash(x),如果不是,沿着链表指针一次查找。
删除操作:分三种情况,假设hash(x)=j,x散列到j
1、j.next=nil,即只有一个元素x散列到slot j,只需将j释放到自由表;
2、j.key=x,且j.next!=nil,x位于j槽,后面还有其他元素,把j.next移动到j,原j.next所占空间释放到自由表
3、j.key!=x且j.next!=nil,x位于j的next指针指向的后面的slot中,修改x前后元素指针,释放x所占slot.
//伪代码
//分配新slot
RemoveFromFreeSlot(s){//s为slot下标,代表槽对象
if(s.prev!=nil)
s.prev.next=s.next;
else free = s.next;
if(s.next!=nil)
s.next.prev=s.prev;
s.flag=1;
return s;
}
//释放slot到FreeList
FreeSlotToFreeList(s){
s.flag=0;
s.next=free;
free.prev=s;
free=s;
s.prev=nil;
}
Insertion(x){
j=hash(x);
if(j.flag==0)//插入一个空槽
RemoveFromFreeSlot(j);
j.next=nil;
j.prev=nil
j.key=x;
else
t=RemoveFromFreeSlot(free);//获取自由链表首位置
if(hash(j.key)==j)//2.a情况,把新元素放到t,修改前后元素指针
t.prev=j;t.key=x;t.next=j.next;
j.next=t;
else //2.b情况
t.key=j.key;t.prev=j.prev;t.next=j.next;//把j中原先的移到t,修改原先元素指针
if(t.next!=nil)t.next.prev=t;
if(t.prev!=nil)t.prev.next=t;
j.key=x;j.next=nil;j.prev=nil;//把x放到j
}
Search(x){
j=hash(x);
//x散列到槽为空,所以不存在x
//j存储的值不属于j,所以不存在x
if(j.flag==0||hash(j.key)!=j)return -1;
while(j!=nil&& j.key!=x)
j=j.next;
return j;
}
Delete(x){
j=hash(x);r=search(x);
if(r<0)return false;//不存在x
if(r==j && j.next==nil){
FreeSlotToFreeList(j);
}
else if(r==j && j.next!=nil){//把j下一位元素移到j,释放下一位元素位置
i=j.next;
j.key=i.key;
j.next=i.next;
if(i.next!=nil)i.next.prev=j;
FreeSlotToFreeList(i);
}
else
r.prev.next=r.next;
if(r.next!=nil)
r.next.prev=r.prev;
FreeSlotToFreeList(r);
}
相关文章推荐
- 算法导论 11.2-4 散列表内未占用槽链接成自由链表
- c++类不含有数据成员(静态除外),则不会为该类实例分配存储空间,该类实例只占用一个字节空间
- 结构体占用字节数及存储与空间分配(转)
- 【C语言】结构体占用字节数及存储与空间分配
- 虚拟机中分配的20G硬盘是否会占用物理20G的硬盘?
- JVM 内存分配模型概念和java中各种对象的存储
- C++内存分配方式详解——堆、栈、自由存储区、全局/静态存储区和常量存储区
- C++内存分配方式详解——堆、栈、自由存储区、全局/静态存储区和常量存储区
- 【转】C++内存分配方式详解——堆、栈、自由存储区、全局/静态存储区和常量存储区
- 操作系统:存储管理动态分区分配及回收算法
- 串的表示和实现(串的堆分配存储、串的定长顺序存储结构)
- C语言动态存储分配空间作为数组
- JVM 内存分配模型概念和java中各种对象的存储
- 内存空间分配 堆、栈、静态存储区的区别
- 连续的磁盘存储空间的分配和回收。
- 串的堆分配存储表示
- 变量的作用域与存储分配
- 串的堆分配存储表示
- 存储管理技术--连续分配
- C++内存分配方式详解——堆、栈、自由存储区、全局/静态存储区和常量存储