查找n个数中最小的k个元素

/* 求n个数中最小的k个元素(n很大,k相对较小)
 * 建立一个k个元素的堆:再逐个插入,最坏情况时间复杂度为O(nlgk)
 */
#include <stdio.h>

/* 求左右叶子、父结点的宏定义 */
#define LEFT(i)		((i) * 2)
#define RIGHT(i) 	((i) * 2 + 1)
#define PARENT(i)	((i) / 2)

/* 维持堆的性质
 * 算法原理:选取当前结点及其子结点3个中的最大值,
 *		跟当前结点交换,并递归
 */
void keep_max_heap(int *heap, int size, int i) {
	int max = i;
	if (LEFT(i) <= size && heap[LEFT(i)] > heap[max]) {
		max = LEFT(i);
	}
	if (RIGHT(i) <= size && heap[RIGHT(i)] > heap[max]) {
		max = RIGHT(i);
	}
	if (i != max) {
		int tmp = heap[max];
		heap[max] = heap[i];
		heap[i] = tmp;
		keep_max_heap(heap, size, max);
	}
}

/* 根据数组建立堆 
 * 算法原理:n/2个元素是第一个非叶子结点,
 * 从该元素往上逐渐调整堆,使之保持堆特性。
 * 为方便,数组第0号元素不用
 */
void build_max_heap(int *heap, int size) {
	for (int i = size / 2; i > 0; i--) {
		keep_max_heap(heap, size, i);
	}
}

/* 大根堆排序,从小到大 */
void max_heap_sort(int *heap, int size) {
	for (int i = size; i > 0; i--) {
		int tmp = heap[i];
		heap[i] = heap[1];
		heap[1] = tmp;
		keep_max_heap(heap, i - 1, 1);
	} //堆排序后从小到大输出
}

/* 打印堆元素 */
void print_heap(int *heap, int size) {
	for (int i = 1; i <= size; i++) {
		printf("%-5d", heap[i]);
	}
	printf("\n");
}

/* 若发现在比大根堆最大值要小的元素,
 * 则用该元素取代堆的根并使堆保持堆特性
 */
void max_heap_replace(int *heap, int size, int value) {
	heap[1] = value;
	keep_max_heap(heap, size, 1);
}

int main() {
	/* 测试 */
	int a[11] = {-1, 67, 7, 34, 5, 69, 24, 78, 58, 62, 64};
	int b[100];
	for (int i = 0; i < 100; i++) {
		b[i] = 100 - i;
	}
	int size = 10;//求0到k大的元素
	build_max_heap(a, size);
	print_heap(a, size);
	for (int i = 0; i < 100; i++) {
		if (b[i] < a[1]) {
			max_heap_replace(a, size, b[i]);
		}
	}
	max_heap_sort(a, size);
	print_heap(a, size);
	return 0;
}

/* 结果为 

78   69   67   62   64   24   34   58   5    7
1    2    3    4    5    5    6    7    7    8

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值