二叉堆--C语言实现

/* binheap.c
 * 二叉堆的结构属性:
 * 必须是一颗完成二叉树。这使得可以用数组来存取二叉堆,但数组大小需要预先估计好。
 * 二叉堆的堆序性:
 * 每个节点关键字的值必须不小于其父节点关键字的值。这使得根节点的关键字值总是最小。
 * nizqsut@163.com
 */

#include
#include

#include "binheap.h"
#include "fatal.h"

#define MIN_PQ_SIZE    (10)
#define MIN_DATA    (-32767) /* 哨兵 */
#define MAX_DATA    (32768)

struct bin_heap
{
    int capacity;
    int size;
    element_type *elements;
};

static int
is_empty( prior_queue h )
{
    return h->size == 0;
}

static int
is_full( prior_queue h )
{
    return h->size == h->capacity;
}

static prior_queue
initialize(int max_elements)
{
    prior_queue h;

    if (max_elements < MIN_PQ_SIZE)
        Error("Priority queue size is to small!");
    

    h = malloc( sizeof( struct bin_heap ) );
    if ( NULL == h)
        Error("Out of space!");

    /* 使用h->elements[0]作为哨兵,因此多分配的一个单元 */
    h->elements = malloc( (max_elements + 1)
                    * sizeof(element_type) );
    if ( NULL == h->elements){
        free(h);
        Error("Out of space!");
    }

    h->capacity = max_elements;
    h->size = 0;
    h->elements[0] = MIN_DATA;

    return h;
}

static void
make_empty(prior_queue h)
{
    h->size = 0;
}

static void
insert( element_type x, prior_queue h)
{
    int i;

    if ( is_full(h) )
        Error("Priority queue is full!");

    /*
    如果空穴的父节点的值比插入值大,则空穴往上移一层;
    否则将插入值填入空穴中。
    */
    for ( i =++h->size; h->elements[i/2] > x; i /= 2){
        h->elements[i] = h->elements[i/2];
    }
    h->elements[i] = x;
}

/*
    删除二叉堆的最小单元
    二叉堆的最小单元就是根节点,删除根节点后需要从子树中寻找一个节点
    来做为根节点。方法是将根节点处的空穴下沉,并将最后那个节点移到合适的空穴上。
*/
static element_type
delete_min( prior_queue h )
{
    int i, child;

    element_type min_element, last_element;

    if ( is_empty( h ) ){
        Error("Priority queue is empty!");
        return h->elements[0];
    }

    min_element = h->elements[1];
    last_element = h->elements[h->size--];

    for ( i = 1; i * 2 <= h->size; i = child ){
        child = i * 2;
        if ( child != h->size && h->elements[child + 1]
            < h->elements[child] )
            child++;

        if ( last_element > h->elements[child] ){
            h->elements[i] = h->elements[child];
        }else{
            break;
        }
    }

    h->elements[i] = last_element;

    return min_element;
}

static element_type
find_min(prior_queue h)
{
    if ( !is_empty(h) )
        return h->elements[1];

    Error("Priority queue is empty!");
    return h->elements[0];
}

static void destroy(prior_queue h)
{
    if ( h == NULL )
        return;

    free( h->elements );
    free( h );
}

static int
get_parent( int pos )
{
    return (pos & 1) ? ( (pos - 1) / 2 ) : ( pos / 2 );
}

/*
 * 降低指定位置关键字的值,根据新值重新调整二叉堆的
 * value 必须是正值!
 */
static int
decrease_key( int pos, int value, prior_queue h)
{
    int i;
    int parent;
    int new_element;

    if ( h == NULL || pos > h->size ){
        Error("Input parameter error!");
        return -1;
    }
   
    i = pos; // + 1;
    new_element = h->elements[i] - value;
   
    for (parent = get_parent(i);  parent > 0; parent = get_parent(i) ){
        if ( new_element < h->elements[parent])
            h->elements[i] = h->elements[parent];
        else
            break;
        i /= 2;
    }
    h->elements[i] = new_element;

    return 0;
}

/*
 * 删除指定位置的节点:
 *        通过先将该位置关键字值降到最小,令其位置调整到根节点上,
 *        在调用delete_min()删除之。
 */
static int
delete_element( int pos, prior_queue h )
{
    if ( decrease_key( pos, MAX_DATA, h) )
        return -1;

    delete_min( h );

    return 0;
}


/************    Next we test binary heap    ***************/

#define get_array_size(array)    ( sizeof(array) / sizeof(array[0]) )

void test_bin_heap(void)
{
    int i;
    int min_element;

    prior_queue h;
    element_type elements[] =
                {3, 12, 11, 8, 9, 6, 5,
                24, 1, 7, 13, 66, 28,
                10, 20, 15, 16, 22, 2};

    h = initialize(64);
    if ( NULL == h )
        return;

    for ( i = 0; i < get_array_size(elements); i++){
        insert(elements[i], h);
    }

    /* test for find_min() */
    min_element = find_min( h );

    /* test for delete_element() */
    delete_element(9, h);

    /* test for delete_min() */
    min_element = delete_min( h );
    min_element = find_min( h );

    destroy( h );
}

/****************************************************************************************************/

/* binheap.h */

#ifndef _BINHEAP_H_
#define _BINHEAP_H_

typedef int element_type;

struct bin_heap;
typedef struct bin_heap *prior_queue;

#endif
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
阅读(531) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言实现优先队列的经典方式是使用二叉堆数据结构。二叉堆是一种完全二叉树,同时满足堆次序的条件。在二叉堆中,每个节点的值都大于或等于其子节点的值(最大堆),或者每个节点的值都小于或等于其子节点的值(最小堆)。通过维护堆次序,可以保证堆顶元素是最大或最小的元素。 下面是C语言实现二叉堆的优先队列的一种方法: ```C #include <stdio.h> #include <stdlib.h> typedef struct { int capacity; // 队列的容量 int size; // 队列中元素的数量 int *data; // 存储队列元素的数组 } PriorityQueue; PriorityQueue* createPriorityQueue(int capacity) { PriorityQueue *queue = (PriorityQueue*)malloc(sizeof(PriorityQueue)); queue->capacity = capacity; queue->size = 0; queue->data = (int*)malloc(sizeof(int) * capacity); return queue; } void destroyPriorityQueue(PriorityQueue *queue) { free(queue->data); free(queue); } void enqueue(PriorityQueue *queue, int value) { if (queue->size >= queue->capacity) { // 队列已满,需要扩容 queue->capacity *= 2; queue->data = (int*)realloc(queue->data, sizeof(int) * queue->capacity); } // 将元素放入队列尾部 queue->data[queue->size] = value; queue->size++; // 通过向上调整操作恢复堆次序 int child = queue->size - 1; int parent = (child - 1) / 2; while (child > 0 && queue->data[child] > queue->data[parent]) { int temp = queue->data[child]; queue->data[child] = queue->data[parent]; queue->data[parent] = temp; child = parent; parent = (child - 1) / 2; } } int dequeue(PriorityQueue *queue) { int value = queue->data[0]; // 将队尾元素放到队首,并删除队尾元素 queue->data[0] = queue->data[queue->size - 1]; queue->size--; // 通过向下调整操作恢复堆次序 int parent = 0; while (parent * 2 + 1 < queue->size) { int leftChild = parent * 2 + 1; int rightChild = parent * 2 + 2; int maxChild = leftChild; if (rightChild < queue->size && queue->data[rightChild] > queue->data[leftChild]) { maxChild = rightChild; } if (queue->data[parent] >= queue->data[maxChild]) { break; } int temp = queue->data[parent]; queue->data[parent] = queue->data[maxChild]; queue->data[maxChild] = temp; parent = maxChild; } return value; } int main() { PriorityQueue *queue = createPriorityQueue(10); enqueue(queue, 5); enqueue(queue, 3); enqueue(queue, 7); printf("%d\n", dequeue(queue)); // 输出7,因为7是队列中的最大值 printf("%d\n", dequeue(queue)); // 输出5,因为5是队列中的次大值 printf("%d\n", dequeue(queue)); // 输出3,因为3是队列中的最小值 destroyPriorityQueue(queue); return 0; } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值