堆的应用

1、优先级队列

(注:在这篇博客里会涉及到一些堆的基本操作,这些堆的基本操作请参考上一篇博客:堆的基本操作(https://blog.csdn.net/A__B__C__/article/details/82818091))

优先级队列,名字叫队列,其实就是用堆来封装的一层而已,个人感觉和队列没有什么关系;

代码如下:

头文件(其中包含了队列的操作,堆排序和top K问题):

#ifndef __HEAP_H__
#define __HEAP_H__

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>

//堆:是一个数组,其中的元素是按照二叉树的顺序在数组中存放的

	//任意一个节点的数据都比其左右孩子都小---小堆
	//任意一个节点的数据都比它的左右孩子大---大堆
typedef int HPDataType;
typedef int (*Compare) (HPDataType pLeft, HPDataType pRight);

typedef struct Heap
{
	HPDataType* _hp;
	int capacity;
	int size;
	Compare _com;
}Heap;

void InitHeap (Heap* hp, Compare Com);//初始化堆
void CreateHeap(Heap* hp, HPDataType* arr, int size, Compare Com);	//创建堆
void AdjustDown (Heap* hp, int parent);	//调整堆(向下调整)
void InsertHeap (Heap* hp, HPDataType data);	//插入
void RemoveHeap (Heap* hp);	//移除元素,(把堆顶元素和最后一个元素交换,size--就把堆顶元素删除了,最后在调整一下堆顶元素)
int SizeHeap (Heap* hp);	//返回堆元素个数
int IsHeapEmpty (Heap* hp);	//判断是不是空堆
HPDataType HeapTop (Heap* hp);	//返回堆顶元素
void AdjustUp (Heap* hp, int child);	//向上调整堆
void Swap (HPDataType* p, HPDataType*q);	//交换两个数
void  CheakHeap (Heap* hp);	//判断堆是否已满,如果满了,就增容;如果没有满,就返回
void DestroyHeap (Heap* hp);	//销毁堆
int Less (HPDataType pLeft, HPDataType pRight);	//小于比较
int Greater (HPDataType pLeft, HPDataType pRight);	//大于比较
///
//堆排序
void HeapSort (Heap *hp);	

///
//top K 问题
void TopKNum (int k);

/
///构造优先级队列
typedef struct PriorityQueue
{
	Heap _q;
}PriorityQueue;

void InitPriorityHeap (PriorityQueue* q, Compare Com);
void PushPriorityQueue(PriorityQueue* q, HPDataType data); 
void PopPriorityQueue(PriorityQueue* q); 
HPDataType TopPriorityQueue(PriorityQueue* q); 
int SizePriorityQueue(PriorityQueue* q); 
int EmptyPriorityQueue(PriorityQueue* q); 

#endif 

优先级队列的操作:

///
//构造优先级队列

void InitHeap (Heap* hp, Compare Com)    //堆的初始化
{
	assert (hp != NULL);
	hp->_hp  = (HPDataType*)malloc (10*sizeof (HPDataType));
	if (hp == NULL)
	{
		perror ("IninHeap :: malloc>>");
		return;
	}
	hp->capacity = 10;
	hp->size = 0;
	hp->_com = Com;
}
void InitPriorityHeap (PriorityQueue* q, Compare Com)	//初始化队列
{
	assert (q != NULL);
	InitHeap (&q->_q, Com);
}

void PushPriorityQueue(PriorityQueue* q, HPDataType data)	//入队列
{
	assert (q != NULL);
	InsertHeap (&q->_q, data);
}
void PopPriorityQueue(PriorityQueue* q)	//出队列
{
	assert (q != NULL);
	RemoveHeap (&q->_q);
}
HPDataType TopPriorityQueue(PriorityQueue* q)	//返回队列对头元素
{
	assert (q != NULL);
	return HeapTop (&q->_q);
}
int SizePriorityQueue(PriorityQueue* q)	//返回队列元素个数
{
	assert (q != NULL);
	SizeHeap (&q->_q);
}
int EmptyPriorityQueue(PriorityQueue* q)	//判断队列对否为空
{
	assert (q != NULL);
	IsHeapEmpty (&q->_q);
}

 

2、堆排序

堆排序就是利用堆删除的方法,将第一个元素和最后一个元素交换,然后size-1,在将堆里剩下的元素进行对调整,调整成一个新堆,一直到堆的size == 0,所有元素都已经排完了;

运行结果如下:

 

 

代码如下:

//堆排序
void HeapSort (Heap *hp)
{
	int i = hp->size;//保存堆元素个数
	while ((hp->size)>0)
	{
                //交换堆中第一个元素和最后一个元素
		Swap (&hp->_hp[0], &hp->_hp[hp->size-1]); 
		hp->size --;    //堆中元素个数减一
		AdjustDown (hp, 0);    //堆调整
	}
	hp->size = i;//排序完之后让size 等原来的个数,这样就把所有元素又存到数组中了
}

3、top K 问题 :在海量数据中找出最大的前k个元素

在大量数据中找出其中最大的前k个数:可以利用堆,先将前k个数用来建堆,剩下的依次次与堆中第一个数比较(因为大堆中第一个数最大,小堆第一个数最小,这里以小堆找前k个最大的数为例),如果遇到比小顶堆的堆顶的值大的,将它放入堆中 最终的堆会是数组中最大的K个数组成的结构,在用堆排序就可以将最大的数按顺序排列

运行结果(这是在随机生成的20个数中找最大的十个数):

 

代码如下:


void TopKNum (int k)
{
	int i = 0;
	Heap hp;
	int* p = NULL;//存放前k个数,用来构造堆
	int rd = 0;
	int a = 0;
	//构造10000个随机数,并存入文件,在从文件中读取
	FILE* pfW = NULL;
	FILE* pfR = NULL;
	srand ((unsigned) time (NULL));
	pfW = fopen ("test.txt", "w");
	if (pfW == NULL)
	{
		perror ("FILE::OPEN >>");
		return;
	}
	for (i=0; i<10000000; i++)// 这里是要生成的随机数个数
	{
		rd = rand();	//构造随机数
		if (i < 10000000-1)
		{
			fprintf(pfW, "%d\t", rd); 
		}
		if (i == 10000000-1)	//最后一个数后面不用在打一个tab键
		{
			fprintf(pfW, "%d", rd);	//把随机数写入文件 
		}
	}
	fclose (pfW);
	//从文件中读取
	pfR = fopen ("test.txt", "r");
	if (pfR == NULL)
	{
		perror ("read::fopen>>");
		return;
	}
	i = 0;
	p = (int*)malloc (k*sizeof (int));
	while (!feof (pfR))
	{
		fscanf(pfR,"%d", &a);
		//取前k个数
		if (i < k)
		{
			p[i] = a;
		}
		//让前k个建堆,把第k+1个入堆
		if (i == k)
		{
			CreateHeap(&hp, p, k, Greater);
		}
		if(i >= k)	//去剩下的数,依次与堆顶元素比较,如果比堆顶元素大,就用它代替堆顶元素,在调整堆
		{
			if (a > hp._hp[0])
		{
			Swap(&a, &hp._hp[0]);
			AdjustDown (&hp, 0);	
		}
		}


		i++;
	}
	fclose (pfR);
	free (p);

	//找完最大的几个数之后再用堆拍一下序
	HeapSort(&hp);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值