python数据结构学习笔记(九)
2015-09-01 19:07
429 查看
Priority Queues
9.1 ADT
9.2 implementing a priority queue
用无序的list来实现
用有序的列表来实现优先队列
9.3 heaps
heap数据结构
使用堆来实现优先队列
基于数组实现的完全二叉树
使用最小优先队列来进行排序
adaptable priority queue
Locators
P.min(): return (k, v)
P.remove_min(): return (k,v)
P.is_empty()
len(P)
优先队列可能有几个元素有相同的key值并且都是最小,这时最小的值是随机选择的一个。
使用最小优先队列来进行排序
可以先构造一个空的优先队列,然后将要排序的元素一个个插入到队列中,然后通过
为了支持这些新的操作,我们需要定义一个新的ADT
Locators
要修改队列中的任意一个元素,我们要能定位到里面的任意一个元素。现在增加定位器Locators, 在添加一个新元素到队列中的时候,返回一个locator给上级函数。
P.update(loc, k, v): 将loc指定位置的key, value更新。
P.remove(loc): 删除指定的元素,并返回(key, value)
class AdaptableHeapPriorityQueue(HeapPriorityQueue):
""" a locator-based priority queue implemented with a binary heap."""
class Locator(HeapPriorityQueue._Item):
__slots__ = '_index'
def __init__(self, k, v, j):
super().__init__(k, v)
self._index = j
# -------------- nonpublic methods -----------------
# override swap to record new indices
def _swap(self, i, j):
super()._swap(i, j)
self._data[i]._index = i
self._data[j]._index = j
def _bubble(self, j):
"""将某个元素上移或者下移到适当的位置"""
if j > 0 and self._data[j] < self._data[self._parent(j)]:
self._upheap(j)
else:
self._downheap(j)
def add(self, key, value):
""" add a key-value pair."""
token = self.Locator(key, value, len(self._data))
self._data.append(token)
self._upheap(len(self._data) - 1)
return token
def update(self, loc, newkey, newval):
j = loc._index
if not (0 <= j < len(self) and self._data[j] is loc):
raise ValueError('invalid locator')
loc._key = newkey
loc._value = newval
self._bubble(j)
def remove(self, loc):
""" remove and return (key, value)"""
j = loc._index
if not (0 <= j < len(self) and self._data[j] is loc):
raise ValueError('invalid locator')
if j == len(self) - 1: # remove the last position
self._data.pop()
else:
self._swap(j, len(self) - 1)
self._data.pop()
self._bubble(j)
return (loc._key, loc._value)
[/code]
9.1 ADT
9.2 implementing a priority queue
用无序的list来实现
用有序的列表来实现优先队列
9.3 heaps
heap数据结构
使用堆来实现优先队列
基于数组实现的完全二叉树
使用最小优先队列来进行排序
adaptable priority queue
Locators
Priority Queues
9.1 ADT
P.add(k, v)P.min(): return (k, v)
P.remove_min(): return (k,v)
P.is_empty()
len(P)
优先队列可能有几个元素有相同的key值并且都是最小,这时最小的值是随机选择的一个。
9.2 implementing a priority queue
用无序的list来实现 对于优先队列里面列表的存储,一种方法是选择前面的PositionalList,这种方法由于队列里面的元素不需要 保持有序,添加一个元素只需要O(1)的时间就可以完成,但是对于min, remove_min操作就需要遍历一次整个list, 找到最小的元素的定位,所以需要O(n)的时间。class UnsortedPriorityQueue(PriorityQueueBase): def _find_min(self): """return Position of item with min key""" if self.is_empty(): raise Empty('priority queue is empty') small = self._data.first() walk = self._data.after(small) while walf is not None: if walf.element() < small.element(): small = walk walk = self._data.after(walk) return small def __init__(self): self._data = PositionalList() def __len__(self): return len(self._data) def add(self, key, value): self._data.add_last(self._Item(key, value)) def min(self): p = self._find_min() item = p.element() return (item._key, item._value) def remove_min(self): """remove and return (k, v) tuple with min key.""" p = self._find_min() item = self._data.delete(p) return (item._key, item._value)
用有序的列表来实现优先队列
使用有序的列表来实现,队列中第一个元素就是最小的元素。的实现。为了保证树的完全性,可以先将根结点与最下一层的最右边的结点进行交换,然后删除 最右下的那个结点。这样做有可能破坏子结点key不小于父结点的性质。维护的方法与插入类似,从根结点开始, 与它的子结点的key进行比较,注意它可能有2个子结点,所以需要与其中key较小那个进行比较。如果根的key值大于 子结点的key值,则进行交换,然后继续判断是否需要进一步交换。最坏情况也是O(logn)的复杂度。9.3 heaps
前面提到的使用有序和无序队列实现的优先队列各有各的优点。使用无序队列的在插入的时候可以达到 O(1)的时间,但是查找最小的元素就要O(n)的时间。有序队列实现的插入时要O(n)的时间,但是 查找最小的元素只需要O(1)的时间。 现在介绍一种新的数据结构,二叉堆,可以在对数的时间复杂的实现插入和查找的操作。 heap数据结构 二叉堆中的元素满足下面的性质: 对于每个不是根的位置p,该位置存储的key大于等于它的父结点上存储的key,这样从根结点开始向下的路径中 的所有key都是不减的,所以根结点的key就是最小的。 完全二叉树性质:一个高度为h的堆T如果在层数0到h-1都是满的,而在第h层可以不满,但是结点从左向右 紧密排列,及左边没有空隙, 那就可以说它是完全的。 一个完全的二叉堆,当里面有n个元素时,它的高度h不超过logn 使用堆来实现优先队列 因为堆的高度不会超过n的对数,如果我们实现更新的操作这个高度,那么就可以实现不超过对数时间的复杂度。 对于使用堆的实现,我们需要关心的是插入一个新的元素该如何操作。为了保持树的完全性,这个新的结点 应该在最下一层的最后一个结点的右边,如果这层刚好满了则在新一层的第一个结点。这样做仅仅满足树的 完全性,但是还要考虑一个结点的key值不小于它的父结点的key的性质。 假设新结点为p,他的父结点为q,如果kp < kq,则需要将这两个结点做一个交换。交换之后p结点仍然可能 小于它新的父结点,则继续检查判断是否要交换,直到p结点被推到根结点或者已经满足性质为止。 因为插入操作最坏的情况是将新结点一直推到根结点的位置,所以时间复杂度是O(logn) 现在到[code]remove_min
基于数组实现的完全二叉树
f(p)是位置p在数组中存储的下标
如果p是根,则f(p) = 0
如果p是位置q的左孩子,则f(p) = 2f(q) + 1
如果p是位置q的右孩子,则f(p) = 2f(q) + 2
使用数组实现有一个好处,就是在找最下层最右边结点的时候非常方便,就是下标n - 1存储的那个位置。
class HeapPriorityQueue(PriorityQueueBase):
"""a min-oriented priority queue implemented with a binary heap."""
def _parent(self, j):
return (j - 1) // 2
def _left(self, j):
return 2 * j + 1
def _right(self, j):
return 2 * j + 2
def _has_left(self, j):
return self._left(j) < len(self._data)
def _has_right(self, j):
return self._right(j) < len(self._data)
def _swap(self, i, j):
"""swap the elements at indices i and j of array"""
self._data[i], self._data[j] = self._data[j], self._data[i]
def _upheap(self, j):
parent = self._parent(j)
if j > 0 and self._data[j] < self._data[parent]:
self._swap(j, parent)
self._upheap(parent) # recur at position of parent
def _downheap(self, j):
if self._has_left(j):
left = self._left(j)
small_child = left
if self._has_right(j):
right = self._right(j)
if self._data[right] < self._data[left]:
small_child = right
if self._data[small_child] < self._data[j]:
self._swap(j, small_child)
self._downheap(small_child)
# ---------------- public methods --------------------
def __init__(self):
self._data = []
def __len__(self):
return len(self._data)
def add(self, key, value):
self._data.append(self._Item(key, value))
self._upheap(len(self._data) - 1)
def min(self):
if self.is_empty():
raise Empty('priority queue is empty')
item = self._data[0]
return (item._key, item._value)
def remove_min(self):
if self.is_empty():
raise Empty('priority queue is empty')
self._swap(0, len(self._data) - 1)
item = self._data.pop()
self._downheap(0)
return (item._key, item._value)
使用最小优先队列来进行排序
可以先构造一个空的优先队列,然后将要排序的元素一个个插入到队列中,然后通过
remove_min不断 从队列中取出元素就可以得到有序的队列。
adaptable priority queue
优先队列现在可以实现移除最小的一个元素,但是实际情况中可能还有一些问题需要处理,如一些在排队的 顾客中,中间的某个人突然说不想继续排了要离开,这时需要能将任意一个元素移除。还有比如排队的某个 客人本来优先级在后面,但是突然拿出一张vip卡,那么他的优先级突然变得很高,需要能将他的key修改为 新的值。为了支持这些新的操作,我们需要定义一个新的ADT
adaptable priority queue.
Locators
要修改队列中的任意一个元素,我们要能定位到里面的任意一个元素。现在增加定位器Locators, 在添加一个新元素到队列中的时候,返回一个locator给上级函数。
P.update(loc, k, v): 将loc指定位置的key, value更新。
P.remove(loc): 删除指定的元素,并返回(key, value)
class AdaptableHeapPriorityQueue(HeapPriorityQueue):
""" a locator-based priority queue implemented with a binary heap."""
class Locator(HeapPriorityQueue._Item):
__slots__ = '_index'
def __init__(self, k, v, j):
super().__init__(k, v)
self._index = j
# -------------- nonpublic methods -----------------
# override swap to record new indices
def _swap(self, i, j):
super()._swap(i, j)
self._data[i]._index = i
self._data[j]._index = j
def _bubble(self, j):
"""将某个元素上移或者下移到适当的位置"""
if j > 0 and self._data[j] < self._data[self._parent(j)]:
self._upheap(j)
else:
self._downheap(j)
def add(self, key, value):
""" add a key-value pair."""
token = self.Locator(key, value, len(self._data))
self._data.append(token)
self._upheap(len(self._data) - 1)
return token
def update(self, loc, newkey, newval):
j = loc._index
if not (0 <= j < len(self) and self._data[j] is loc):
raise ValueError('invalid locator')
loc._key = newkey
loc._value = newval
self._bubble(j)
def remove(self, loc):
""" remove and return (key, value)"""
j = loc._index
if not (0 <= j < len(self) and self._data[j] is loc):
raise ValueError('invalid locator')
if j == len(self) - 1: # remove the last position
self._data.pop()
else:
self._swap(j, len(self) - 1)
self._data.pop()
self._bubble(j)
return (loc._key, loc._value)
[/code]
相关文章推荐
- 数据结构——单人名单
- 数据结构:线索树之基本例程(1)
- 数据结构(三):链表的Java实现
- 后缀表达式树
- 大整数的加乘多项式运算
- 数据结构 3 栈和队列
- 数据结构学习之路-第二章:带头结点的线性链表
- 数据结构 (一)——宏观导论
- 数据结构中排序算法-归并排序(4)
- 数据结构与算法-简介
- vijos-P1083 小白逛公园
- 数据结构与算法分析Java版练习2.1和2.2
- poj3687 Labeling Balls 拓扑排序
- 数据结构基础笔记(三)【严蔚敏】
- 数据结构与算法分析Java版练习1.15
- 数据结构(二):队列的Java实现
- 数据结构与算法分析Java版练习1.14
- 【Matlab学习笔记】(六)基本数据结构(矩阵定义方法)
- 数据结构--线性表
- 数据结构(一):栈的Java实现