您的位置:首页 > 编程语言 > Python开发

其他题目---设计一个没有扩容负担的堆结构

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指针:

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  设计 结构 python
相关文章推荐