堆排序简述
堆
堆是一种基于树的数据结构,其父节点总是大于(最大堆)或小于(最小堆)其子节点,并且其根节点总是树中最小(或最大)的那个节点。
堆排序常被用来实现优先队列
,用于按给定的因子排定元素的优先级。而其本身最常采用的实现方式是扁平储存的二叉树。在二叉树实现的堆中,一个节点的兄弟节点并无特定的关系。唯一的关系存在于父节点和子结点中。
由于堆的二叉树总会是一个完全二叉树,且是用列表的方式扁平储存二叉树以实现堆,所以,在堆的列表中,序号为 n 的节点有以下几个特征:
- 其父节点为
(n - 1) // 2
(取整)。 - 其左子节点为
n * 2 + 1
。 - 其右子节点为
n * 2 + 2
。
操作
插入
对堆执行插入操作,只需将其推入列表尾部,然后逐一与其父节点进行比较,如果逆序就交换。直到不再交换,则节点已经在正确为止。
关键代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 def heap_up(self, index):
parent = self.parent(index)
while True:
if not self.compare(self._heap[parent], self._heap[index]):
self._heap[parent], self._heap[index] = \
self._heap[index], self._heap[parent]
else:
break
index = parent
parent = self.parent(index)
if index == parent:
break
def insert(self, node):
self._heap.append(node)
self.size += 1
self.heap_up(self.size - 1)
提取
提取堆中最大的一个元素,只需提取第一个元素,然后用最后一个元素覆盖第一个元素。再逐一将这个元素与和这个元素差距最大的子元素比较,如果逆序就交换。直到不再交换为止,删除最后一个元素,返回提取出来的第一个元素。操作完毕。
关键代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 def heap_down(self, index=0):
while True:
child = self.max_child(index)
if not child:
break
else:
if self.compare(self._heap[child], self._heap[index]):
self._heap[child], self._heap[index] = \
self._heap[index], self._heap[child]
index = child
else:
break
def extract(self):
top = self._heap[0]
self._heap[0] = self._heap[self.size - 1]
self.heap_down()
self._heap.pop()
self.size -= 1
return top
参考
《算法精解-C语言描述》
https://en.wikipedia.org/wiki/Heap_(data_structure)
完整代码
托管在gist上:
https://gist.github.com/Arianxx/17d97f0bad4512aae483395bba46a5f9