求n个数据中的中间大小的1个或2个数。
可以建两个大小都是n / 2的堆。第一个堆是小顶堆,第二个堆是大顶堆。要求大顶堆的堆顶元素 < 小顶堆的堆顶元素,如果不符合,就交换两个堆的堆顶元素,维护这两个堆。最后,两个堆的堆顶元素就是n个数据中的中间大小的2个数。
对于这个数组arr来说,前一半的空间用来建立小顶堆;后一半的空间建立大顶堆。对于这个小顶堆,如果某一个元素的编号是i,则它的左儿子的编号是:2 * i + 1; 右儿子的编号是:2 * i + 2。对于这个大顶堆,如果某一个元素的编号是i,则它的左儿子的编号是[i - (size / 2 - 1)] * 2 + 1 + size / 2 - 1 - 1 = 2 * i - size / 2 + 1; 右儿子的编号是 2 * i - size / 2 + 2。
下面对这个过程进行分解:先把前一半数据当成一个小顶堆,后一半数据当成一个大顶堆。然后对这两组数据进行完整的调整,得到小顶堆和大顶堆。
由于要求小顶堆的堆顶数据比大顶堆的堆顶数据大,所以要交换两个堆顶数据。之后对这两组数据重新调整,使它们重新符合小顶堆和大顶堆的定义。
重复上述过程。
重复上述过程。
重复上述过程。最终得到如下两个堆,我们可以发现最大的4个数已经集中到小顶堆上,而最小的5个数集中到大顶堆。这时小顶堆和大顶堆的堆顶元素就是所有数中的中位数。
中位数的求解代码如下:
#include <stdio.h>
#include <stdlib.h>
int arr [] = {
1, 2, 3, 4, 5, 6, 7, 8, 9};
int sizeOfMinHeap = 0; //小顶堆的大小
int sizeOfMaxHeap = 0; //大顶堆的大小
int size = 0; //数组的大小
void swap(int i, int j) //交换数组arr中编号为i和j的两个元素
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
//寻找3个元素中的最小值
int getMinForMinHeap(int