堆排序

       堆数据结构是一种数组对象,它可以看为是一棵完全二叉树。树中每个节点与数组中存放该节点值的那个元素对应。除最后一层外,树的每一层都是填满的。对数组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;
		}
	}
}
参考《算法导论》第六章堆排序


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值