现在的位置: 首页 > 综合 > 正文

使用最大堆和最小堆实现中位数的查找

2013年10月09日 ⁄ 综合 ⁄ 共 3223字 ⁄ 字号 评论关闭

参考链接:双堆维护数组中位数

用堆维护中位数的意思是说,设计两个堆,第一个堆(大顶堆)存放小于中位数的元素,第二个堆(小顶堆)存放大于中位数的元素。

下面是双堆维护中位数的语言描述:
1、初始化的时候设置两个变量分别记录两个堆【左堆和右堆】的元素的个数。
2、取第一个元素d[0]作为初始中位数m。
3、循环后面的每一个元素,如果比m大,则插入到右堆,如果比m小,则插入到左堆。
4、.如果此时最小堆和最大堆的元素个数的差值>=2 ,则将m加入到元素个数少的堆中,然后从元素个数多的堆将根节点赋值到m,最后重建两个最大堆和最小堆,返回到3。
此时,如果想要知道当前的中位数,若左右队的元素个数相等,则输出堆顶元素的平均值,否则输出堆元素个数较大堆的堆顶元素。


C代码实现:

// 寻找中位数
#include <stdio.h>

#define LEFT(i) (i*2)
#define RIGHT(i) (i*2+1)
#define PARENT(i) (i / 2);
#define MAXLINE 256

/* 使用最大堆和最小堆实现中位数的查找
参考链接:http://www.jishu521.com/post/imzooer/8010506.html
求数组中位数的方法:
用堆维护中位数的意思是说,设计两个堆,第一个堆(大顶堆)存放小于中位数的元素,第二个堆(小顶堆)存放大于中位数的元素。

下面是双堆维护中位数的语言描述:
1、初始化的时候设置两个变量分别记录两个堆【左堆和右堆】的元素的个数。
2、取第一个元素d[0]作为初始中位数m。
3、循环后面的每一个元素,如果比m大,则插入到右堆,如果比m小,则插入到左堆。
4、.如果此时最小堆和最大堆的元素个数的差值>=2 ,则将m加入到元素个数少的堆中,然后从元素个数多的堆将根节点赋值到m,最后重建两个最大堆和最小堆,返回到3。

此时,如果想要知道当前的中位数,若左右堆的元素个数相等,则输出左右堆顶元素的平均值,否则输出堆元素个数较大堆的堆顶元素。
*/
int findMediansByHeap(int arr[], int max_heap[], int min_heap[]);

void swap(int *a, int *b)
{
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
}

void maxHeapify(int h[], int i)
{
    int max, len;
    int l, r;
    len = h[0];
    max = i;
    l = LEFT(i);
    r = RIGHT(i);
    if (l <= len && h[max] < h[l])
        max = l;
    if (r <= len && h[max] < h[r])
        max = r;
    if (i != max)
    {
        swap(h+i, h+max);
        maxHeapify(h, max);
    }
}

void buildMaxHeap(int h[])
{
    int len, i;
    len = h[0];
    for (i = len/2; i > 0; i--)
    {
        maxHeapify(h, i);
    }
}

void maxHeapInsert(int heap[], int key)
{
    int i, p;
    heap[0]++;
    heap[heap[0]] = key;
    i = heap[0];
    p = PARENT(i);
    while (p > 0 && heap[p] < heap[i])
    {
        swap(heap+i, heap+p);
        i = p;
        p = PARENT(i);
    }
}

int maxHeapPop(int heap[])
{
    int max;
    max = heap[1];
    heap[1]=heap[heap[0]];
    heap[0]--;
    maxHeapify(heap, 1);
    return max;
}

void maxHeapSort(int heap[])
{
    int len, i;
    buildMaxHeap(heap);
    while ( (len = heap[0]) > 0)
    {
        swap(heap+1, heap+len);
        heap[0]--;
        maxHeapify(heap, 1);
    }
}

void minHeapInsert(int heap[], int key)
{
    int i, p;
    heap[0]++;
    heap[heap[0]] = key;
    i = heap[0];
    p = PARENT(i);
    while (p > 0 && heap[p] > heap[i])
    {
        swap(heap+i, heap+p);
        i = p;
        p = PARENT(i);
    }
}

void minHeapify(int h[], int i)
{
    int max, len, l, r;
    len = h[0];
    max = i;
    l = LEFT(i);
    r = RIGHT(i);
    if (l <= len && h[max] > h[l])
        max = l;
    if (r <= len && h[max] > h[r])
        max = r;
    if (i != max)
    {
        swap(h+i, h+max);
        minHeapify(h, max);
    }
}

int minHeapPop(int heap[])
{
    int min;
    min = heap[1];
    heap[1]=heap[heap[0]];
    heap[0]--;
    minHeapify(heap, 1);
    return min;
}

void buildMinHeap(int h[])
{
    int len, i;
    len = h[0];
    for (i = len/2; i > 0; i--)
    {
        minHeapify(h, i);
    }
}

void printArray(int a[])
{
    int len = a[0];
    int i;
    for (i = 1; i <= len; i++)
    {
        printf("%d ", a[i]);
    }
    printf("\n");
}

int findMediansByHeap(int arr[], int max_heap[], int min_heap[])
{
    int i, m;

    for (i = 1, m = arr[i]; i <= arr[0]; i++)
    {
        if(m < arr[i])
            minHeapInsert(min_heap, arr[i]);
        else
            maxHeapInsert(max_heap, arr[i]);

        if (max_heap[0] - min_heap[0] == 2)
        {
            // 如果大顶堆元素个数-小顶堆元素个数=2,则删除大顶堆的首元素并将改元素添加到小顶堆中
            m = maxHeapPop(max_heap);
            minHeapInsert(min_heap, m);
        }
        else if (min_heap[0] - max_heap[0] == 2)
        {
            // 如果小顶堆元素个数-大顶堆元素个数=2,则删除小顶堆的首元素并将改元素添加到大顶堆中
            m = minHeapPop(min_heap);
            maxHeapInsert(max_heap, m);
        }
    }
    if (max_heap[0] == min_heap[0])
        return ( (max_heap[1]+min_heap[1]) / 2);
    else if(max_heap[0] > min_heap[0])
        return max_heap[1];
    else
        return min_heap[1];
}

int main()
{
    //int arr[] = {0,10,20,30,40,50,60,70,200};
    int arr[] = {0,200,30,40,10,70,20,60};
    int len = sizeof(arr) / sizeof(arr[0]) - 1;
    arr[0] = len;
    int max_heap[MAXLINE];
    int min_heap[MAXLINE];
    int res;
    max_heap[0] = 0; // 初始化堆大小
    min_heap[0] = 0;

    printf("Original array:\n");
    printArray(arr);
    res = findMediansByHeap(arr, max_heap, min_heap);
    printf("After maximum heap sort, new array:\n");
    maxHeapSort(arr);
    arr[0] = len;
    printArray(arr);
    printf("The medians is: %d\n", res);

    return 0;
}

抱歉!评论已关闭.