堆
堆数据结构是一种数组对象,它可以看为是一棵完全二叉树。树中每个节点与数组中存放该节点值的那个元素对应。除最后一层外,树的每一层都是填满的。对数组A[1 ... n],则节点i的左右子节点分别为left(i),right(i),其父节点为parent(i),其定义如下:
#define left(i) (i << 1)
#define right(i) ((i << 1) + 1)
#define parent(i) (i >> 1)
考虑到大多数编程语言数组都是以0作为起点,故对于数组A[0 ... n],则节点i的left(i),right(i)和parent(i)定义如下:
#define left(i) (((i) << 1) + 1)
#define right(i) (((i) << 1) + 2)
#define parent(i) (((i) - 1) >> 1)
堆可以分为大根堆(最大堆)和小根堆(最小堆)。在大根堆中,除了根节点以外的其他节点i,有A[parent(i)] >= A[i],即某个节点的值小于等于父节点的值。小根堆与大根堆正好相反,除了根节点以外的其他节点i,有A[parent(i)] <= A[i],即某个节点的值大于等于父节点的值。
堆排序可以分为堆化、建堆和排序三个步骤。堆化用于保持堆的性质;建堆用于建立堆,对于数组,可以通过从后往前调用堆化过程来建立堆;排序用于将数据按一定顺序排列,该排序过程是每次将根节点与最后的叶子节点调换,并减少堆节点的个数,调用堆化保持堆的性质。
#define ant_right_child(x) (((x) << 1) + 2)
#define ant_left_child(x) (((x) << 1) + 1)
#define ant_parent(x) (((x) - 1) >> 1)
#define ant_swap(a, b, size) \
do { \
size_t __size = (size); \
char *__a = (a), *__b = (b); \
do { \
char __tmp = *__a; \
*__a++ = *__b; \
*__b++ = __tmp; \
} while (--__size > 0); \
} while(0)
void ant_heapsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *))
{
size_t l, r, largest;
int i, j;
/* 建立堆 */
for (j = size - 1; j >= 0; --j) {
i = j;
while (1) { /* 堆化--保持堆的性质 将子节点中的数据与父节点数据比较 并交换(需要交换)*/
l = ant_left_child(i);
r = ant_right_child(i);
if (l < size && compar(base + l * nmemb, base + i * nmemb) > 0)
largest = l;
else
largest = i;
if (r < size && compar(base + r * nmemb, base + largest * nmemb) > 0)
largest = r;
if (largest == i) break;
ant_swap(base + i * nmemb, base + largest * nmemb, nmemb);
i = largest;
}
}
/* 堆排序 */
for (j = size - 1; j >= 1; --j) {
ant_swap(base, base + j * nmemb, nmemb); /* 取走最大或最小值 (与最后的叶子节点交换) */
--size;
i = 0;
while (1) { /* 交换后,节点的值可能不满足对的性质,调用堆化过程保持堆的性质 */
l = ant_left_child(i);
r = ant_right_child(i);
if (l < size && compar(base + l * nmemb, base + i * nmemb) > 0)
largest = l;
else
largest = i;
if (r < size && compar(base + r * nmemb, base + largest * nmemb) > 0)
largest = r;
if (largest == i) break;
ant_swap(base + i * nmemb, base + largest * nmemb, nmemb);
i = largest;
}
}
}
参考《算法导论》第六章堆排序