二叉堆的C语言实现

堆是一颗完全树,同时满足每个节点均大于或小于它的子节点,这样的数据结构被称为最大堆或者最小堆。 这种结构处于一种半排序状态,它的存取效率从整体上讲介于有序和无序之间。当对象处于动态时,是种非常有优势的数据结构。存取的时间复杂为log(a,n),其中a为完全树的度。

通常二叉堆以数组存储,层为 log(2,n),可以使用以下的代码来定义二叉堆结构。

typedef struct binary_heap_s* binary_heap_pt;

typedef struct binary_heap_s {
    int size;
    int current;
    Item *data;
} binary_heap_t;

当以数组存储时,二叉堆的父子节点下标存在如下关系。

第一个元素索引为0:

  • 索引为i的左孩子的索引是 (2*i+1);
  • 索引为i的右孩子的索引是 (2*i+2);
  • 索引为i的父结点的索引是 floor((i-1)/2);

第一个元素索引为1:

  • 索引为i的左孩子的索引是 (2*i);
  • 索引为i的右孩子的索引是 (2*i+1);
  • 索引为i的父结点的索引是 floor(i/2);

以下代码都按第一个元素索引为0方式

添加元素图解

在堆中添加元素时需要执行向上堆化操作,假设在最小堆中添加35,需要执行以下步骤。

图一

图二

图三

图四

代码实现如下:

/* 
 *        Name:  fixup
 * Description:  向上堆化
 * 
 */
static void 
fixup(binary_heap_pt heap, int k)
{
    while (k>0 && item_cmp(heap->data[(k - 1) / 2],heap->data[k])) {
        swap(heap->data, k, (k - 1) / 2);
        k = (k - 1) / 2;
    }
}

int 
binary_heap_push(binary_heap_pt heap, Item element)
{
    if (heap == NULL) {
        return 0;
    }
    if (heap->current == heap->size) {
        return 0;
    }
    heap->data[heap->current] = element;
    fixup(heap, heap->current++);
    return 1;
}

删除堆顶元素图解

在堆中移除堆顶元素时需要执行向下堆化操作,假设在最小堆中移除堆顶完素,需要执行以下步骤。

图一

图二

图三

图四

代码实现如下:

/* 
 *        Name:  fixdown
 * Description:  向下堆化
 * 
 */
static void 
fixdown(binary_heap_pt heap, int k, int end)
{
    int temp;
    while (k*2 + 1 <= end) {
        temp = k*2 + 1;
        if (temp < end && item_cmp(heap->data[temp], heap->data[temp + 1])) {
            temp++;
        }
        if (!item_cmp(heap->data[k], heap->data[temp])) {
            break;
        }
        swap(heap->data, k, temp);
        k = temp;
    }
}

Item 
binary_heap_pop(binary_heap_pt heap)
{
swap(heap->data, 0, heap->current - 1);
fixdown(heap, 0, heap->current - 2);
return heap->data[--heap->current];
}

完整源码

/* binary_heap.h */
#ifndef BINARY_HEAP_H
#define BINARY_HEAP_H

typedef int Item;
typedef struct binary_heap_s* binary_heap_pt;

typedef struct binary_heap_s {
    int size;
    int current;
    Item *data;
} binary_heap_t;

binary_heap_pt binary_heap_init(int size);
void binary_heap_free(binary_heap_pt heap);
void binary_heap_print(binary_heap_pt heap);
int binary_heap_push(binary_heap_pt heap, Item element);
Item binary_heap_pop(binary_heap_pt heap);
Item binary_heap_top(binary_heap_pt heap);
int binary_heap_empty(binary_heap_pt heap);

#endif

binary_heap.h

/* binary_heap.c */
/*
 * =====================================================================================
 *
 *       Filename:  binary_heap.c
 *
 *    Description:  二叉堆实现
 *
 *        Version:  1.0
 *        Created:  2016-09-19 20:08
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  simon
 *
 * =====================================================================================
 */

#include <stdio.h>
#include <stdlib.h>

#include "binary_heap.h"

static void 
swap(Item *data, int a, int b)
{
    Item c;
    c = data[a];
    data[a] = data[b];
    data[b] = c;
}

/* 
 * 最小堆 ((a) > (b))
 * 最大堆 ({a} < (b))
 * 
 */
#define item_cmp(a, b) ((a) > (b)) /* 最小堆 */

/* 
 *        Name:  fixup
 * Description:  向上堆化
 * 
 */
static void 
fixup(binary_heap_pt heap, int k)
{
    while (k>0 && item_cmp(heap->data[(k - 1) / 2],heap->data[k])) {
        swap(heap->data, k, (k - 1) / 2);
        k = (k - 1) / 2;
    }
}

/* 
 *        Name:  fixdown
 * Description:  向下堆化
 * 
 */
static void 
fixdown(binary_heap_pt heap, int k, int end)
{
    int temp;
    while (k*2 + 1 <= end) {
        temp = k*2 + 1;
        if (temp < end && item_cmp(heap->data[temp], heap->data[temp + 1])) {
            temp++;
        }
        if (!item_cmp(heap->data[k], heap->data[temp])) {
            break;
        }
        swap(heap->data, k, temp);
        k = temp;
    }
}

binary_heap_pt 
binary_heap_init(int size)
{
    if (size<=0) {
        return NULL;
    }
    binary_heap_pt heap_pt = malloc(sizeof(binary_heap_t));
    heap_pt->data = malloc(sizeof(Item)*size);
    heap_pt->size = size;
    heap_pt->current = 0;
    return heap_pt;
}

void 
binary_heap_free(binary_heap_pt heap)
{
    if (heap == NULL) {
        return;
    }
    free(heap->data);
    free(heap);
}

void 
binary_heap_print(binary_heap_pt heap)
{
    int i;
    if (heap == NULL) {
        return;
    }
    for (i=0; i<heap->size; i++) {
        printf("%d ", heap->data[i]);
    }
}

int 
binary_heap_push(binary_heap_pt heap, Item element)
{
    if (heap == NULL) {
        return 0;
    }
    if (heap->current == heap->size) {
        return 0;
    }
    heap->data[heap->current] = element;
    fixup(heap, heap->current++);
    return 1;
}

Item 
binary_heap_pop(binary_heap_pt heap)
{
    swap(heap->data, 0, heap->current - 1);
    fixdown(heap, 0, heap->current - 2);
    return heap->data[--heap->current];
}

Item 
binary_heap_top(binary_heap_pt heap)
{
    return heap->data[0];
}

int
binary_heap_empty(binary_heap_pt heap)
{
    return heap->current == 0;
}

binary_heap.c

/* binary_heap_test.c */
#include <stdlib.h>
#include <stdio.h>

#include "binary_heap.h"

#define LENGTH(a) ( (sizeof(a)) / (sizeof(a[0])) )

int
main(int argc, char *argv[])
{
    int a[] = {10, 40, 30, 60, 90, 70, 20, 50, 80};
    int i, len=LENGTH(a);
    binary_heap_pt heap = NULL;
    heap = binary_heap_init(LENGTH(a) + 10);

    printf("\n== 空堆检查: %d", binary_heap_empty(heap));
    printf("\n== 插入数据: ");
    for(i=0; i<len; i++)
    {
        printf("%d ", a[i]);
        binary_heap_push(heap, a[i]);
    }
    printf("\n== 空堆检查: %d", binary_heap_empty(heap));

    printf("\n== 最 小 堆: ");
    binary_heap_print(heap);

    i=35;
    binary_heap_push(heap, i);
    printf("\n== 添加元素: %d", i);
    printf("\n== 最 小 堆: ");
    binary_heap_print(heap);

    printf("\n== 堆顶元素: %d\n", binary_heap_top(heap));

    i = binary_heap_pop(heap);
    printf("\n== 删除元素: %d", i);
    printf("\n== 最 小 堆: ");
    binary_heap_print(heap);
    printf("\n");
    i = binary_heap_pop(heap);
    printf("\n== 删除元素: %d", i);
    printf("\n== 最 小 堆: ");
    binary_heap_print(heap);
    printf("\n");
    binary_heap_free(heap);
    return 0;
}

binary_heap_test.c

测试程序的运行结果

== 空堆检查: 1
== 插入数据: 10 40 30 60 90 70 20 50 80 
== 空堆检查: 0
== 最 小 堆: 10 40 20 50 90 70 30 60 80 0 0 0 0 0 0 0 0 0 0 
== 添加元素: 35
== 最 小 堆: 10 35 20 50 40 70 30 60 80 90 0 0 0 0 0 0 0 0 0 
== 堆顶元素: 10

== 删除元素: 10
== 最 小 堆: 20 35 30 50 40 70 90 60 80 10 0 0 0 0 0 0 0 0 0

== 删除元素: 20
== 最 小 堆: 30 35 70 50 40 80 90 60 20 10 0 0 0 0 0 0 0 0 0

转载文章请注明出处: http://mingnote.com


Date 2016-07-04(星期一) 23:13 By Ming In 算法 Tags 算法,