堆的基本算法及应用。

今天我来介绍一下堆的基本算法和它的一些简单应用。

一 。基本算法:

#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;
}

以上就是有关堆的问题,谢谢参观。



猜你喜欢

转载自blog.csdn.net/ymk1507050118/article/details/80998646