用c实现小顶堆,堆元素类型问int。最大容量为100。随后的文章我将会用c++模板技术改写这个程序,使他能够适应更多数据类型。
这篇文章主要是呈现C代码,不会对原来过多解释。二叉堆原理详见我的博客http://blog.csdn.net/bdss58/article/details/40742817
首先定义堆的数据结构,堆元素用数组存储:
// 堆结构体,元素类型暂定int
typedef struct
{
// 当前堆中元素的个数
int heap_size;
// 用数组存储元素
int values[MAX_ITEMS];
}int_heap;
还有定义初始化函数,删除元素函数和添加元素函数。
上面的一些定义就可以构成一个完整的头文件了,heap.h:
#ifndef HEAP_H
#define HEAP_H
// 最多可以存储元素的个数
#define MAX_ITEMS 100
// 堆结构体,元素类型暂定int
typedef struct
{
// 当前堆中元素的个数
int heap_size;
// 用数组存储元素
int values[MAX_ITEMS];
}int_heap;
// 初始化堆
void init_heap(int_heap* root);
// 取得堆的首元素,并删除之
int get_first_value(int_heap* root);
// 往堆中加入新元素
void add_value(int_heap* root,int value);
#endif // HEAP_H
接下来就该实现头文件中定义的函数了。
为了实现添加和删除,需要一些辅助函数。
sift_up()"提升函数”,当从堆中添加元素时,用它来调整堆;
// sift_up function “上升”调整堆
void sift_up(int_heap* root,int index)
{
assert(root!=NULL);
int parent_index=PARENT(index);
assert(parent_index>=0);
if(index==0)
{
return;
}
if(root->values[parent_index]>root->values[index])
{
swap_values(root,parent_index,index);
if(parent_index!=0)
{
sift_up(root,parent_index);
}
}
}
sift_down“下沉函数”,当从堆中删除元素时,用它来调整堆。
// sift_down function “下潜”调整堆
void sift_down(int_heap* root,int index)
{
int left_child=LEFT_CHILD(index);
int right_child=RIGHT_CHILD(index);
if(left_child>root->heap_size)
{
// 说明没有左右孩子,终结条件,返回
return;
}
if(right_child>=root->heap_size)
{
// 说明只有左孩子
if(root->values[index]>root->values[left_child])
{
swap_values(root,index,left_child);
sift_down(root,left_child);
}
}
else
{
// 接下来说明左右孩子都有
if(root->values[index]>root->values[left_child] || root->values[index]>root->values[right_child])
{
int min_index;
if(root->values[left_child]>root->values[right_child])
{
min_index=right_child;
}
else
{
min_index=left_child;
}
swap_values(root,index,min_index);
sift_down(root,min_index);
}
}
}
整个heap.c文件:
/**
* 实现小顶堆
* 作者:bdss58
* BSD 许可证
* 你可以拿去随便修改使用
* */
#include <assert.h>
#include <stdlib.h>
#include "heap.h"
// 注意加括号
#define LEFT_CHILD(index) (2*(index)+1)
#define RIGHT_CHILD(index) (2*(index)+2)
#define PARENT(index) (((index)-1)/2)
// swap_values function 交换两个变量的值
void swap_values(int_heap* root,int i,int j)
{
int temp;
// 检查参数合法性
assert(root != NULL);
assert(i>=0 && i<root->heap_size);
assert(j>=0 && j<root->heap_size);
assert(i != j);
temp=root->values[i];
root->values[i]=root->values[j];
root->values[j]=temp;
}
// sift_down function “下潜”调整堆
void sift_down(int_heap* root,int index)
{
int left_child=LEFT_CHILD(index);
int right_child=RIGHT_CHILD(index);
if(left_child>root->heap_size)
{
// 说明没有左右孩子,终结条件,返回
return;
}
if(right_child>=root->heap_size)
{
// 说明只有左孩子
if(root->values[index]>root->values[left_child])
{
swap_values(root,index,left_child);
sift_down(root,left_child);
}
}
else
{
// 接下来说明左右孩子都有
if(root->values[index]>root->values[left_child] || root->values[index]>root->values[right_child])
{
int min_index;
if(root->values[left_child]>root->values[right_child])
{
min_index=right_child;
}
else
{
min_index=left_child;
}
swap_values(root,index,min_index);
sift_down(root,min_index);
}
}
}
// sift_up function “上升”调整堆
void sift_up(int_heap* root,int index)
{
assert(root!=NULL);
int parent_index=PARENT(index);
assert(parent_index>=0);
if(index==0)
{
return;
}
if(root->values[parent_index]>root->values[index])
{
swap_values(root,parent_index,index);
if(parent_index!=0)
{
sift_up(root,parent_index);
}
}
}
void init_heap(int_heap *root)
{
assert(root != NULL);
root->heap_size=0;
}
// 取得第一个元素,并删除之
int get_first_value(int_heap *root)
{
int result;
assert(root != NULL);
assert(root->heap_size>0);
result=root->values[0];
root->heap_size--;
if(root->heap_size!=0)
{
root->values[0]=root->values[root->heap_size];
sift_down(root,0);
}
return result;
}
void add_value(int_heap *root, int value)
{
assert(root != NULL);
// 保证已经初始化堆
assert(root->heap_size>=0);
assert(root->heap_size<MAX_ITEMS);
root->values[root->heap_size]=value;
root->heap_size++;
// sift_up function “上升”调整
if(root->heap_size-1 != 0)
{
sift_up(root,root->heap_size-1);
}
}
这时,可以在main.c中做测试了:
#include <stdio.h>
#include <stdlib.h>
#include "heap.h"
int main(void)
{
int_heap h;
init_heap(&h);
int i;
srand(11);
// 按最大容量将heap填满
for(i=0;i<MAX_ITEMS;i++)
{
add_value(&h,rand()%1000);
}
int lastval=get_first_value(&h);
printf("Value 0=%d\n",lastval);
for(i=1;i<MAX_ITEMS;i++)
{
int val=get_first_value(&h);
printf("Value %d=%d\n",i,val);
if(val<lastval)
{
printf("out error\n");
}
lastval=val;
}
return 0;
}