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