其他题目---设计一个没有扩容负担的堆结构
2017-11-06 09:14
531 查看
【题目】
堆结构一般是使用固定长度的数组结构来实现的。这样的实现虽然足够经典,但存在扩容的负担,比如不断向堆中增加元素,使得固定数组快耗尽时,就不得不申请一个更大的固定数组,然后把原来数组中的对象复制到新的数组中完成堆的扩容,所以,如果扩容时堆中的元素个数为N,那么扩容行为的时间复杂度为O(N)。请设计一种没有扩容负担的堆结构,即在任何时刻有关堆的操作时间复杂度都不超过O(logN)。
【要求】
没有扩容的负担。
可以生成小根堆,也可以生成大根堆。
包含getHead方法,返回当前堆顶的值。
包含getSize方法,返回当前堆的大小。
包含add(x)方法,即向堆中添加新的元素x,操作后依然是大/小根堆。
包含popHead方法,即删除并返回堆顶的值,操作后依然是大/小根堆。
如果堆中的节点个数为N,那么各个方法的时间复杂度为:
getHead: O(1)
getSize: O(1)
add: O(logN)
poHead: O(logN)
【基本思路】
使用完全二叉树结构来实现堆,二叉树的节点类型如下,比经典的二叉树节点多一条指向父节点的parent指针:
利用二叉树结构重写堆方法即可,具体参照代码。
【代码实现】
堆结构一般是使用固定长度的数组结构来实现的。这样的实现虽然足够经典,但存在扩容的负担,比如不断向堆中增加元素,使得固定数组快耗尽时,就不得不申请一个更大的固定数组,然后把原来数组中的对象复制到新的数组中完成堆的扩容,所以,如果扩容时堆中的元素个数为N,那么扩容行为的时间复杂度为O(N)。请设计一种没有扩容负担的堆结构,即在任何时刻有关堆的操作时间复杂度都不超过O(logN)。
【要求】
没有扩容的负担。
可以生成小根堆,也可以生成大根堆。
包含getHead方法,返回当前堆顶的值。
包含getSize方法,返回当前堆的大小。
包含add(x)方法,即向堆中添加新的元素x,操作后依然是大/小根堆。
包含popHead方法,即删除并返回堆顶的值,操作后依然是大/小根堆。
如果堆中的节点个数为N,那么各个方法的时间复杂度为:
getHead: O(1)
getSize: O(1)
add: O(logN)
poHead: O(logN)
【基本思路】
使用完全二叉树结构来实现堆,二叉树的节点类型如下,比经典的二叉树节点多一条指向父节点的parent指针:
class HeapNode: def __init__(self, value): self.value = value self.left = None self.right = None self.parent = None
利用二叉树结构重写堆方法即可,具体参照代码。
【代码实现】
#python3.5
class HeapNode: def __init__(self, value): self.value = value self.left = None self.right = None self.parent = None
class MyHeap:
def __init__(self, comp):
self.head = None #堆头节点
self.last = None #堆尾节点
self.size = 0 #当前堆的大小
self.comp = comp #基于比较器决定是大根堆还是小根堆
def getHead(self):
return self.head.value if self.head != None else None
def getSize(self):
return self.size
def isEmpty(self):
return True if self.size == 0 else False
#添加一个新节点到堆中
def add(self, value):
newNode = HeapNode(value)
if self.size == 0:
self.head = newNode
self.last = newNode
self.size = 1
return
node = self.last
parent = node.parent
#找到尾节点的下一个位置并插入新节点
while parent != None and parent.left != node:
node = parent
parent = node.parent
if parent == None:
nodeToAdd = self.mostLeft(self.head)
nodeToAdd.left = newNode
newNode.parent = nodeToAdd
elif parent.right == None:
parent.right = newNode
newNode.parent = parent
else:
nodeToAdd = self.mostLeft(parent.right)
nodeToAdd.left = newNode
newNode.parent = nodeToAdd
self.last = newNode
#建堆过程及其调整
self.heapInsertModify()
self.size += 1
def heapInsertModify(self):
node = self.last
parent = node.parent
if parent != None and self.comp(parent.value, node.value):
self.last = node.parent
while parent != None and self.comp(parent.value, node.value):
self.swapClosedTwoNode(node, parent)
parent = node.parent
if self.head.parent != None:
self.head = self.head.parent
def swapClosedTwoNode(self, node, parent):
if node == None or parent == None:
return
parentParent = parent.parent
parentLeft = parent.left
parentRight = parent.right
nodeLeft = node.left
nodeRight = node.right
node.parent = parentParent
if parentParent != None:
if parentParent.left == parent:
parentParent.left = node
else:
parentParent.right = node
parent.parent = node
if nodeLeft != None:
nodeLeft.parent = parent
if nodeRight != None:
nodeRight.parent = parent
if node == parentLeft:
node.left = parent
node.right = parentRight
if parentRight != None:
parentRight.parent = node
else:
node.left = parentLeft
node.right = parent
if parentLeft != None:
parentLeft.parent = node
parent.left = nodeLeft
parent.right = nodeRight
def mostLeft(self,node):
while node.left != None:
node = node.left
return node
def mostRight(self, node):
while node.right != None:
node = node.right
return node
def popHead(self):
if self.size == 0:
return None
res = self.head
if self.size == 1:
self.head = None
self.last = None
self.size = 0
return res.value
oldLast = self.popLastAndSetPreviousLast() #返回尾节点并更新尾节点
#如果弹出尾节点,堆的大小等于1的处理
if self.size == 1:
self.head = oldLast
self.last = oldLast
return res.value
#如果弹出尾节点,堆的大小大于1的处理
headLeft = res.left
headRight = res.right
oldLast.left = headLeft
if headLeft != None:
headLeft.parent = oldLast
oldLast.right = headRight
if headRight != None:
headRight.parent = oldLast
res.left = None
res.right = None
self.head = oldLast
#堆heapify过程
self.heapify(self.head)
return res.value
def heapify(self, node):
left = node.left
right = node.right
most = node
while left != None:
if left != None and self.comp(most.value, left.value):
most = left
if right != None and self.comp(most.value, right.value):
most = right
if most == node:
break
else:
self.swapClosedTwoNode(most, node)
left = node.left
right = node.right
most = node
if node.parent == self.last:
self.last = node
while node.parent != None:
node = node.parent
self.head = node
def popLastAndSetPreviousLast(self):
node = self.last
parent = node.parent #以下是寻找尾节点的上一个节点
while parent != None and parent.right != node:
node = parent
parent = node.parent
if parent == None:
node = self.last
parent = node.parent
node.parent = None
if parent != None:
parent.left = None
self.last = self.mostRight(self.head)
else:
newLast = self.mostRight(parent.left)
node = self.last
parent = node.parent
node.parent = None
if parent.left == node:
parent.left = None
else:
parent.right = None
self.last = newLast
self.size -= 1
return node
相关文章推荐
- 设计一个没有扩容负担的堆结构
- 其他题目---一种消息接受并打印的结构设计
- 其他题目---设计可以变更的缓存结构
- 微信公号“架构师之路”学习笔记(五)-数据库扩展性架构设计(水平切分,秒级扩容,平滑迁移,在线表结构变更,一个大数据量多属性高并发的数据库设计等)
- 其他题目---设计RandomPool结构
- 一个典型的采集服务器体系结构设计
- YT03-递推求解课后题目-1004 计算直线的交点数-(6.7日-烟台大学ACM预备队解题报告)分析: 将n 条直线排成一个序列,两条直线最多只有一个交点,三条直线最多有两个交点,直线n 和其他n
- 一个开源的IoC采集服务器体系结构设计
- 一个没有完成的多线程题目
- 数据结构课程设计题目十二_计算机学院学生会的打印机(优先队列)
- 随笔:设计一个栈结构,使得取出栈中最大值时间复杂度为O(1)
- 百度2017年暑假实习生编程题目(第二题)----2、页面调度 在计算机中,页式虚拟存储器实现的一个难点是设计页面调度(置换)算法。其中一种实现方式是FIFO算法。
- 一个开源的IoC采集服务器体系结构设计
- 有三个桶,两个大的可装8斤的水,一个小的可装3斤的水,现在有16斤水装满了两大桶就是8斤的桶,小桶空着,如何把这16斤水分给4个人,每人4斤。没有其他任何工具,4人自备容器,分出去的水不可再要回来。
- Theano与其他深度学习框架的比较,主要强调一系列低水平的设计选择,没有特别顺序。
- 一个开源的IoC采集服务器体系结构设计
- 首次在没有参考解析的情况下完成了一个leetcode题目!
- 数据结构课程设计题目
- ASP.NET#在设计窗口上添加了一个SqlDataSource控件后,没有显示出来?
- 数据结构课程设计题目3