堆的基本概念 :
堆总是一棵完全二叉树。
正常的数组存储 :
改为堆存储后 : 大堆 arry[] = {9 , 17 , 65 , 23 , 45 , 78 , 87 , 53 , 31};
小堆 arry[] = {87 , 78 , 53 , 45 , 65 , 9 , 31 , 17 , 23};
小堆(大堆)中 :任一结点的关键码均小于(大于)等于它的左右孩子的关键码,位于堆顶结点的关键码最小(最大),
从根节点到每个结点的路径上数 组元素组成的序列都是递增(递减)的堆存储在下标为0开始的数组中,因此在
堆中给定下标为i的结点时 ;
堆支持以下的基本 :
HeapInit: 建立一个堆 ;
HeapPush: 向堆中插入一个新元素 , 将新元素提升使其符合堆的性质 ;
HeapTop:获取当前堆顶元素的值 ;
HeapPush:删除堆顶元素,使删除堆顶元素的堆再次成为堆 ;
HeapDestory: 堆的销毁 ;
堆的基本应用 :
Heap.h
代码如下 :
#pragma once
#include
#include
#include
#include
#include
typedef int HPDataType;
//堆的数据结构
typedef struct Heap
{
HPDataType* _a;
int _size;
int _capacity;
}Heap;
//堆的初始化
void HeapInit(Heap* hp, HPDataType* a, int n);
//堆的销毁
void HeapDestory(Heap* hp);
//入堆
void HeapPush(Heap* hp, HPDataType x);
//出堆
void HeapPop(Heap* hp);
//取堆头元素
HPDataType HeapTop(Heap* hp);
//堆的大小
int HeapSize(Heap* hp);
//判断堆是否为空
int HeapEmpty(Heap* hp);
// 不要直接调Heap
void HeapSort(HPDataType* a, int n);
//测试
void TestHeap();
Heap.c
代码如下 :
#include "Heap.h"
//数据交换
void Swap(HPDataType* child, HPDataType* parent)
{
HPDataType ret;
assert(child&&parent);
ret = *child;
*child =* parent;
*parent = ret;
}
//向下调整
//当我们要建小堆时,只需要将向下(向上)调整中判断孩子代表的数值大于父亲代表的数值
//改为小于即可
void AdjustDown(HPDataType*a, int n, int place)
{
int child = 0;
int parent = 0;
assert(a);
parent = place;
//计算出要调节数组中的孩子下标
child = parent * 2 + 1;
while (child < n)
{
//计算出孩子中的最大值
if ((child + 1a[child]))
++child;
//如果孩子的数值大于父亲的数值,则交换两者数值
//并且更新孩子和父亲所代表的坐标,继续向下调整
if (a[child]>a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
break;
}
}
//向上调整
void AdjustUp(HPDataType *a, int place)
{
int child = 0;
int parent = 0;
assert(a);
child = place;
//计算出要调节数组中的父亲下标
parent = (child - 1) / 2;
while (child > 0)
{
//如果孩子的数值大于父亲的数值,则交换两者数值
//并且更新孩子和父亲所代表的坐标,继续向上调整
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
break;
}
}
//堆的初始化
void HeapInit(Heap* hp, HPDataType* a, int n)
{
int parent = 0;
int i = 0;
assert(hp&&a);
hp->_a = (HPDataType*)malloc(sizeof(HPDataType)*n);
assert(hp->_a);
hp->_capacity = n;
hp->_size = 0;
for (i = 0; i < n; i++)
{
hp->_a[i] = a[i];
hp->_size++;
}
//根据堆的性质计算出最后一个父亲的数组下标,表示要调整的位置
//从最后一个父亲下标开始调整,不断更新,直到为堆顶为止
for (parent = (n - 2) / 2; parent >= 0; parent--)
AdjustDown(hp->_a, n, parent);
}
//销毁
void HeapDestory(Heap* hp)
{
assert(hp);
free(hp->_a);
hp->_a = NULL;
hp->_capacity = hp->_size = 0;
}
//入堆
//入堆时将要入堆的元素向上调整
void HeapPush(Heap* hp, HPDataType x)
{
assert(hp);
if (hp->_capacity == hp->_size + 1)
{
hp->_capacity *= 2;
hp->_a = (HPDataType*)realloc(hp->_a, sizeof(HPDataType)*hp->_capacity);
assert(hp->_a);
}
hp->_a[hp->_size++] = x;
AdjustUp(hp->_a, hp->_size - 1);
}
//出堆
//将堆顶元素出堆之后,只需要将数组中的最后一个元素好堆顶元素交换
//然后删除数组的最后一个元素,再将新的堆顶元素向下调整即可
void HeapPop(Heap* hp)
{
assert(hp);
Swap(&hp->_a[0], &hp->_a[hp->_size- 1]);
AdjustDown(hp->_a, --hp->_size-1, 0);
}
//取堆头元素
HPDataType HeapTop(Heap* hp)
{
assert(hp);
return hp->_a[0];
}
//堆的大小
int HeapSize(Heap* hp)
{
assert(hp);
return hp->_size;
}
//堆是否为空
int HeapEmpty(Heap* hp)
{
assert(hp);
return hp->_a > 0 ? 1 : 0;
}
//打印
void HeapPrint(Heap* hp)
{
int i = 0;
assert(hp);
for (i = 0; i < hp->_size; i++)
printf("%d ", hp->_a[i]);
printf("\n");
}
//将数组从小到大排序
// 不要直接调Heap
//利用之前的向上调整,将数组高造成一个大堆,然后数组的第一个元素就是数组中的最大值
//将数组的第一个元素和最后一个元素交换,再将数组从第一个位置向下调整,这时数组的第
//一个元素又代表调整后数组中的最大值,再继续与后面的元素交换直到要调整的位置只剩下
//一个元素位置,数组排序结束(记得没次更新要调整数组的大小)
void HeapSort(HPDataType* a, int n)
{
int parent = 0;
int size = n-1;
int i = 0;
assert(a);
for (parent = (n - 2) / 2; parent >= 0; parent--)
AdjustDown(a, n, parent);
while (size > 0)
{
Swap(&a[0], &a[size--]);
//size代表的要调整数组的大小
AdjustDown(a,size+1,0);
}
for (i = 0; i < n; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void TestHeap()
{
Heap hp;
int n = 0;
HPDataType a[] = {53, 17, 78, 9, 45, 65, 87, 23, 31};
n = sizeof(a) / sizeof(a[0]);
HeapInit(&hp, a, n);
HeapPrint(&hp);
HeapSort(a, n);
}
Test.c
代码如下 :
#include "Heap.h"
int main()
{
TestHeap();
system("pause");
return 0;
}