今天我来介绍一下堆的基本算法和它的一些简单应用。
一 。基本算法:
#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
#include<Windows.h>
typedef struct Heap{
int array[100];
int size;
}Heap;
//堆的初始化。
void HeapInit(Heap *pH,int array[],int size)
{
assert(pH);
memcpy(pH->array,array,sizeof(int)*size);
pH->size=size;
}
//交换函数。
void swap(int *a,int *b)
{
*a^=*b;
*b^=*a;
*a^=*b;
}
//向下调整求大堆的递归法。
void AdjustDown(Heap *pH,int parent)
{
int left=2*parent+1; //先算出要调整节点的左右子树。
int right=2*parent+2;
int Max;
if(left>=pH->size) //当为叶子结点时,直接返回。
{
return;
}
Max=left; //假设最大值是左子树。
if(right<pH->size && pH->array[right]>pH->array[left]) //如果右子树存在并且比左子树大,就让最大值为右子树。
{
Max=right;
}
if(pH->array[Max]>pH->array[parent]) //如果最大值大于要调整节点,就进行交换。
{
swap(pH->array+Max,pH->array+parent);
}
else{
return;
}
AdjustDown(pH,Max); //递归进行这个操作即可。
}
//向下调整求大堆的非递归法。
void AdjustDownLoop(Heap *pH,int parent) //总体上与递归一样,只是加了一个循环。
{
int left;
int right;
int Max;
while(1){
left=2*parent+1;
right=2*parent+2;
if(left>=pH->size)
{
return;
}
Max=left;
if(right<pH->size && pH->array[right]>pH->array[left])
{
Max=right;
}
if(pH->array[Max]>pH->array[parent])
{
swap(pH->array+Max,pH->array+parent);
}
else{
return;
}
parent=Max;
}
}
//造大堆。
void MakeHeap(Heap *pH)
{
int i;
for(i=(pH->size-2)/2;i>=0;i--) //从最后一个叶子节点的父节点开始进行调整,就可得到堆了。
{
AdjustDown(pH,i);
}
}
//求堆顶元素。
int HeapTop(Heap *pH)
{
return pH->array[0]; //直接返回堆顶元素即可。
}
//求堆的元素个数。
int HeapCount(Heap *pH)
{
return pH->size; //直接返回节点个数。
}
//判空。1为空,0不为空。
int HeapIsEmpty(Heap *pH)
{
return pH->size==0?1:0;
}
//出堆。
void HeapPop(Heap *pH)
{
assert(pH);
pH->array[0]=pH->array[pH->size-1]; //让最后一个节点代替第一个节点。
pH->size--;
AdjustDownLoop(pH,0); //整体大小-1,并对第一个节点进行向下调整重新得到堆。
}
//向上调整递归法。
void AdjustUp(Heap *pH,int child)
{
int parent=(child-1)/2; //先求出调整节点的父节点。
if(child==0)
{
return; //如果调整节点为0,则直接返回。
}
if(pH->array[child]>pH->array[parent]) //如果调整节点大于父节点,则进行交换。
{
swap(pH->array+parent,pH->array+child);
}
else{
return;
}
AdjustUp(pH,parent); //递归执行。
}
//向上调整非递归。
void AdjustUpLoop(Heap *pH,int child)
{
int parent;
while(1){
parent=(child-1)/2;
if(child==0)
{
break;
}
if(pH->array[child]>pH->array[parent])
{
swap(pH->array+parent,pH->array+child);
}
else{
return;
}
child=parent;
}
}
//入堆。
void HeapPush(Heap *pH,int data)
{
assert(pH);
pH->array[pH->size++]=data; //直接将值放在最后一个节点的后面,整体+1,在进行调整形成新的堆。
AdjustUpLoop(pH,pH->size-1);
}
二。简单应用:
//建大堆非递归法。
void AdjustArray(int array[],int size,int root)
{
int left;
int right;
int Max;
while(1){
left=2*root+1;
right=2*root+2;
if(left>=size)
{
return;
}
Max=left;
if(right<size && array[right]>array[left])
{
Max=right;
}
if(array[Max]>array[root])
{
swap(array+Max,array+root);
}
else{
return;
}
root=Max;
}
}
//在array中找到最小的k个数。
int *Find(int array[],int size,int k)
{
int i;
int *a=(int *)malloc(sizeof(int)*k); //先开辟k个空间。
for(i=0;i<k;i++)
{
a[i]=array[i]; //将数组中的前k个数放进去。
}
for(i=(k-2)/2;i>=0;i--)
{
AdjustArray(a,k,i); //在对新数组进行调整得到新的堆。
}
i=k;
while(i<size)
{
if(array[i]<a[0]) //循环比较堆顶和原数组剩下的数。
{
a[0]=array[i]; //如果原数组中的数小,就将它放在堆顶,在进行调整得到新的堆。
AdjustArray(a,k,0);
}
i++;
}
return a; //返回数组的地址即可。
}
//排序堆。
void HeapSort(int array[],int size)
{
int i;
for(i=(size-2)/2;i>=0;i--) //建大堆。
{
AdjustArray(array,size,i);
}
for(i=0;i<size-1;i++) //将堆顶与最后一个元素交换,再将除了最后一个元素之外的数进行重新建堆。
{
swap(array+0,array+(size-1-i));
AdjustArray(array,size-1-i,0);
}
printf("该堆从小到大的顺序为:");
for(i=0;i<size;i++) //输出从小到大的顺序。
{
printf("%d ",array[i]);
}
}
三。调试结果:
int main()
{
Heap heap; //定义个堆。
int i;
int array[] = { 53, 17, 78, 9, 45, 65, 87, 23, 31 }; //要进行调整的数组。
int size = sizeof(array) / sizeof(int); //求元素个数。
HeapInit(&heap, array, size); //先初始化。
MakeHeap(&heap); //建堆。
printf("原始堆为:");
for (i = 0; i < heap.size; i++) { //输出原始堆。
printf("%d ", heap.array[i]);
}
printf("\n");
HeapPush(&heap,50); //插入一个元素50,在输出新堆。
printf("入堆后的新堆为:");
for (i = 0; i < heap.size; i++) {
printf("%d ", heap.array[i]);
}
HeapPop(&heap); //删除堆顶,输出新堆。
printf("\n");
printf("出堆后的新堆为:");
for (i = 0; i < heap.size; i++) {
printf("%d ", heap.array[i]);
}
printf("\n");
printf("堆顶为%d\n",HeapTop(&heap)); //输出堆顶元素。
printf("堆的元素个数为%d\n",HeapCount(&heap)); //输出堆的元素个数。
printf("\n");
printf("最小的3个数为:");
for(i=0;i<3;i++)
{
printf("%d ",*(Find(array,size,3)+i)); //输出最小的K个数。
}
printf("\n");
HeapSort(array,size);
printf("\n");
printf("Heap\n");
system("pause");
return 0;
}
以上就是有关堆的问题,谢谢参观。