堆排序
最差时间复杂度 | |
---|---|
最优时间复杂度 | |
平均时间复杂度 | |
最差空间复杂度 | total, auxiliary |
(图片引自维基百科)
个人理解的堆排序:欲对data[0,size)进行堆排序,1)对数组建大根堆(或小根堆),使之符合堆序性(父节点恒大于子节点)与结构性(完全二叉树);2)将根节点(最大元素)与未有序的最后一个节点i交换,交换后data[i,size)已有序;3)将根节点下滤以恢复大根堆的堆序性;4)回到步骤2),直至未有序部分只剩一个节点。
在建大根堆时,有两种方法:1)为满足堆序性从最后一个内部节点开始将全部内部节点下滤;2)从第一个节点开始将全部节点上滤以满足堆序性。其中,方法1)时间复杂度为∑height(i),方法二的时间复杂度为∑depth(i)。在二叉树结构中高度小(深度大)的节点更多,复杂度为高度和的方法1)在效率上更好一些。
算法代码:
inline int parent(int i) {return ((i) - 1) >> 1;}
inline int leftChild(int i) {return ((i) << 1) + 1;}
inline int rightChild(int i) {return ((i) << 1) + 2;}
void heapSort(int data[], int size)
{ /* 对data[]进行堆排序 */
void buildMaxHeap(int[], int);
void percolateDown(int[], int, int);
/* 建大根堆 */
buildMaxHeap(data, size);
while (size)
{
/* 将第一个元素与未排序的最后一个元素交换 */
int max = data[0];
data[0] = data[size - 1];
data[size - 1] = max;
/* 将交换后的第一个元素下滤以恢复大堆堆序性 */
percolateDown(data, --size, 0);
}
}
void buildMaxHeap(int data[], int size)
{ /* 建大根堆 */
void percolateDown(int[], int, int);
/* 从最后一个内部节点开始,将所有内部节点下滤 */
for (int i = parent(size - 1); i >= 0; i--)
{
percolateDown(data, size, i);
}
}
void percolateDown(int data[], int size, int index)
{ /* 将序号为index的元素下滤以恢复大根堆堆序性 */
int maxChild;
int tmp = data[index];
while (leftChild(index) < size)
{
maxChild = (rightChild(index) < size && data[leftChild(index)] < data[rightChild(index)]) ? rightChild(index) : leftChild(index);
if (tmp >= data[maxChild])
{
break;
}
data[index] = data[maxChild];
index = maxChild;
}
data[index] = tmp;
}