堆及堆的应用

Heap.h

#ifndef _HEAP_H_
#define _HEAP_H_

typedef int DataType;

#include<assert.h>
#include<stdlib.h>

typedef int (*Pcompare)(DataType left, DataType right);

typedef struct Heap
{
	DataType *hp;
	int capacity;
	int size;
	Pcompare compare;
}Heap;

typedef struct QueuePri
{
	Heap Pri;
}QueuePri;

int Less(DataType left, DataType right);
int Greater(DataType left, DataType right);
void CreatHeap(Heap *q, int *arr, int size,Pcompare compare);
void DownAdjust(Heap *q, int parent, int size);
void HeapPush(Heap *q, DataType data);
void RemoveHeap(Heap *q);
void MaxKnum(Heap *q, int K);
void HeapSort(Heap *q);

#endif _HEAP_H_

heap.c

#include"Heap.h"

//判断小于的函数
int Less(DataType left, DataType right)
{
	return (left) < (right);
}
//判断大于的函数
int Greater(DataType left, DataType right)
{
	return (left) > (right);
}

//交换两个值
void Swap(DataType *ret, DataType *cur)
{
	DataType tmp = *ret;
	*ret = *cur;
	*cur = tmp;
}
//向下调整
void DownAdjust(Heap *q, int parent, int size)
{
	int child  = (parent<<1)+1;
	assert(q);
	//当孩子的序号大于元素个数时,调整完成
	while(child < size)
	{
		//判断当前节点有没有右孩子,如果有右孩子,比较左右孩子哪一个较小
		//用child记录较小值的序号
		if(child+1 < size && q->compare((q->hp[child+1]),q->hp[child]))
		{
			child +=1;
		}
		//然后,如果双亲节点大于孩子节点的话,让双亲节点与较小的孩子节点交换值
		//然后,将双亲节点等于孩子节点的序号,然后再把左孩子的节点序号复值给孩子节点,这样一直向下调整
		if(q->compare((q->hp[child]) , q->hp[parent]))
		{
			Swap(&q->hp[parent], &q->hp[child]);
			parent = child;
			child = (parent<<1)+1;
		}
		//如果双亲节点的值小于孩子节点,那么就不用再调整
		else
		{
			return;
		}
	}
}
//创建堆
void CreatHeap(Heap *q, int *arr, int size, Pcompare compare)
{
	int i = 0;
	DataType *ret = NULL;
	assert(q);
	ret = (DataType *)malloc(sizeof(int)*size);
	if(ret == NULL)
	{
		assert(0);
	}
	q->hp = ret;
	q->compare = compare;
	//将数组内的数据拷入堆内
	for(i = 0; i < size; i++)
	{
		q->hp[i] = arr[i];
	}
	q->capacity = size;
	q->size = size;
	//对于有孩子节点的节点进行向下调整
	for(i = (size-2)/2; i >= 0; i--)
		DownAdjust(q, i, size);
}
//堆的增容
void Capacityexpan(Heap *q)
{
	int i = 0;
	DataType *ret = NULL;
	assert(q);
	ret = (DataType *)malloc(sizeof(DataType)*(q->capacity<<1));
	if(NULL == ret)
	{
		assert(0);
	}
	//将原空间的数据拷贝如新空间中
	for(i = 0; i < q->size; i++)
	{
		ret[i] = q->hp[i];
	}
	free(q->hp);
	q->hp = ret;
	q->capacity *= 2;
}
//堆的插入
void HeapPush(Heap *q, DataType data)
{
	int child = 0;//记录插入节点的下标
	int parent = 0;//记录插入节点的双亲的下标
	//判断堆是否还有容量
	if(q->capacity == q->size)
	{
		Capacityexpan(q);
	}
	q->hp[q->size] = data;
	q->size += 1;
	child = q->size-1;
	parent = (child-1)>>1;
	//向上调整法
	//用插入的节点与自己的双亲节点比较,如果比双亲节点小的话,就交换,然后再与交换后的双亲比较,直到调整到根节点时停止
	while(child)
	{
		//判断孩子节点的值与其双亲的值那个大,如果双亲的值大于孩子的值,交换孩子与双亲的值
		if(q->compare((q->hp[child]) , q->hp[parent]))
		{
			Swap(&q->hp[child], &q->hp[parent]);
			child = parent;
			parent = (child-1)>>1;
		}
		//如果双亲的值小于孩子的值的话,代表此时,堆是有序的,不用调整
		else
			return;
	}
}
//删除
//用最后一个节点的值代替堆顶的值,将元素的个数减一
//然后进行向下调整
void RemoveHeap(Heap *q)
{
	assert(q);
	//将堆顶的元素替换为堆底的元素
	q->hp[0] = q->hp[q->size-1];
	q->size -= 1;
	DownAdjust(q, 0, q->size);
}
//取堆顶的元素
DataType HeapTopCell(Heap *q)
{
	assert(q);
	return q->hp[0];
}
//取堆底的元素
DataType HeapBase(Heap *q)
{
	assert(q);
	return q->hp[q->size-1];
}
//判断堆是否为空
int EmptyHeap(Heap *q)
{
	assert(q);
	return q->size == 0;
}
//堆的销毁
void DestroyHeap(Heap *q)
{
	assert(q);
	free(q->hp);
	q->hp = NULL;
}
//给出海量的数据,求最大的K个数)
//给出海量的数据,求最大的K个数)
void MaxKnum(Heap *q, int K)
{
	int i = K;
	DataType *ret = NULL;
	assert(q);
	ret = (DataType *)malloc(sizeof(DataType)*K);
	if(ret == NULL)
	{
		assert(0);
	}
	q->hp = ret;
	//首先取前K个数,用这K个数来创建一个小堆
	for(i = 0; i < K; i++)
	{
		int tmp = rand()%10000;
		q->hp[i] = tmp;
	}
	q->size = K;
	q->capacity = K;
	for(i = (K-2)/2; i >= 0; i--)
		DownAdjust(q, i, K);
	//然后,一个一个的取数组内剩下的数,取出的数与堆顶的元素比较,如果比堆顶的元素大的话,就用取出的元素
	//代替堆顶的元素,代替之后再进行向下的调整,使堆重新满足小堆的特性,然后再从数组内取数据,重复上述操作,直到所有的数组为空时
	for(i = K; i < 10000-K; i++)
	{
		int tmp = rand()%10000;
		if(tmp > q->hp[0])
		{
			Swap(&tmp, &q->hp[0]);
			DownAdjust(q, 0, K);
		}
	}
}

//堆排序
//如果是降序的话, 建一个小堆
//然后,先将小堆的堆顶的值与堆底的值交换,这样最小值就到了堆底,然后调整的元素个数-1,向下法调整交换后的堆
//调整好的堆最小值又在堆顶,然后再次与最后的元素交换,直到元素个数为0时停止
void HeapSort(Heap *q)
{
	int  i = q->size;
	assert(q);
	i = q->size;
	while(i)
	{
		//交换堆底和堆顶的元素
		Swap(&q->hp[i-1], &q->hp[0]);
		//把最小值放到堆底之后,元素个数-1;
		--i;
		//调整剩下的几个元素的堆
		DownAdjust(q, 0, i);
	}
}
//堆的初始化
void HeapInit(QueuePri *q, Pcompare compare)
{
	Heap *ret = NULL;
	assert(q);
	//刚开始给十个元素的空间
	ret = (Heap*)malloc(sizeof(DataType)*10);
	if(NULL == ret)
	{
		assert(0);
		return ;
	}
	q->Pri.compare = compare;
	q->Pri.size = 0;
	q->Pri.capacity = 3;
}


   //队列的优先级
//队列的初始化
void InitPriorityQueue(QueuePri* q)
{
	assert(q);
	HeapInit(q, Less);
}
//队列的插入
void PushPriorityQueue(QueuePri *q, DataType data)
{
	assert(q);
	HeapPush(&q->Pri, data);
}
//队列的删除
void PopPriorityQueue(QueuePri *q)
{
	assert(q);
	RemoveHeap(&q->Pri);
}
//队头元素
void PriorityQueueTopNode(QueuePri *q)
{
	assert(q);
	HeapTopCell(&q->Pri);
}
//队列是否为空
int EmptyPriorityQueue(QueuePri *q)
{
	assert(q);
	return EmptyHeap(&q->Pri);
}
//队列的元素个数
int SizePriorityQueue(QueuePri *q)
{
	assert(q);
	return q->Pri.size;
}

Heap.c

#include"Heap.h"

void HeapText()
{
	Heap q = {0};
	Heap cur = {0};
	int a[] = {1,2,3,4,5,6,7,8,9,11,22,41};
	int arr[] = {3,4,2,9,7,8,1};
	CreatHeap(&q, arr, sizeof(arr)/sizeof(arr[0]), Less);
	HeapPush(&q, 5);
	RemoveHeap(&q);
	MaxKnum(&cur,5);
	HeapSort(&q);
        DestroyHeap(&q);
}

int main()
{
	HeapText();
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值