@vourdalak
2019-04-22T15:58:29.000000Z
字数 2123
阅读 983
CS161
数据结构会影响算法的复杂度,以Selection Sort为例。Selection Sort伪代码如下:
def selectionSort(L):
while L is not empty:
find and remove smallest element x in L
output x
在伪代码中即使是一行,一句可以表示的东西,实际使用算法逻辑可能是很多句的复杂结构。
如果用基础的方法,每次扫描整个数组L寻找最小值,那么这个算法的复杂度为:扫描整个L中全部n个元素的时间O(n),执行此步骤n次。
Priority Queue是为寻找/移除最小元素优化过的数据结构。它会把元素根据某种函数映射成可比较的优先级,按优先级排列所有元素。
在选择排序中,需要用到的运算有:
一般情况下Priority Queue常用的运算还有:
Priority Queue最常见的实现方法是使用Binary heap。Binary heap需要O(n)复杂度来生成,每次寻找/删除最小值只需要O(log n)复杂度。就可以把选择排序的整体复杂度下降至。
最小堆是一个完全二叉树。它在实际的结构上是一个从0开始的列表,但是在概念上是一个树的结构。这就要求每个元素在列表中的索引(Index)要能够满足某些特征以来表示树的结构。
[img]
每个节点都可能有子节点(child)或父节点(parent)。没有子节点的是叶节点(leaf),没有父节点的是根节点(root)。一个节点至多可有2个子节点,1个父节点。
假设物理结构列表名为A,A[i]是一个列表元素,也是一个概念结构的节点,这个A[i]在概念结构的父节点为A[(i-1)//2]。e.g. (5-1)//2=2,(6-1)//2=2,则节点5和节点6同为节点2的子节点。这里所指的都是节点在物理结构列表中的索引。A[i]在概念结构的子节点为A[2*i+1]和/或A[2*i+2]。最小堆的性质(heap property)为父节点的优先级必小于等于子节点的优先级。因为堆的性质只限定了父节点和子节点的关系,所以一个满足堆性质的堆未必在物理结构上就是排好序的,左子节点可能大于右子节点。
[img]
但是因为这个性质,根节点永远为堆中最小值,也就是物理结构列表中的A[0]一定是最小值。
既然A[0]一定是当前堆的最小值,直接移除根节点并输出就可以了。摘取最后一个元素放在根节点上,这样会打破A[0]-A1,A[2]的堆的性质,但是其他部分不会受影响。所以迭代地把A[0]的大值交换到下面就好了。这个过程,定义一个函数fixheap(i),i是某个节点的序号,fixheap的作用是修复以x为根节点的子树的堆的性质。
def fixheap(x):
while A[i] has a smaller child:
j = the index of smallest child of A[i]
swap A[i] and A[j]
i = j (then it can continue to the next level)
每一次输出A[0],然后执行fixheap[0],直到序列为空。
每次交换会把i赋值成2i+1或2i+2,此过程进行x次后。但是i必须小于列表长度n所以x不可能大于log n。所以每一次输出A[0]后fixheap[0]的复杂度是。
把整个队列n个元素全部输出即为,选择排序复杂度。
这个过程可以由递归(recursion)或迭代(iteration)完成。定义一个函数makeHeap(i)。
def makeHeap(i):
# reorganize subtree under i into a heap structure
call makeHeap on each child of i
fixheap(i)
使用Master Theorem:
定义T(n)为递归地从长度为n的列表生成最小堆的时间。
for i in n-1, n-2, ..., 0:
fixheap(i)