/* 求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
*/
查找n个数中最小的k个元素
最新推荐文章于 2021-02-20 07:51:47 发布