首先我简单的介绍一下有关堆的性质:
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元 素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足: Ki <= K2*i+1 且 Ki<= K2*i+2 (Ki >= K2*i+1 且 Ki >= K2*i+2) i = 0,1,2…,则称为小堆(或大堆)。
小堆(大堆)中:任一结点的关键码均小于(大于)等于它的左右孩子的关键 码,位于堆顶结点的关键码最小(最大),从根节点到每个结点的路径上数 组元素组成的序列都是递增(递减)的
堆存储在下标为0开始的数组中,因此在堆中给定下标为i的结点时:
如果i=0,结点i是根节点,没有双亲节点;否则结点i的双亲结点为 结点(i-1)/2 如果2 * i + 1 <= n - 1,则结点i的左孩子为结点2 * i + 1,否则结 点i无左孩子 如果2 * i + 2 <= n - 1,则结点i的右孩子为结点2 * i + 2,否则结 点i无右孩子
接下来我们开始创建堆(以大堆为列):
首先我们需要一个数组 int a[]={53,17,78,9,45,65,87,23,31}
然后把它抽象成一棵完全二叉树结构,然后进行调整
typedef int HeapDateType;
typedef struct Heap
{
HeapDateType* _a;
size_t _size;
size_t _capacity;
}Heap;
void HeapInit(Heap* hp, HeapDateType* a, size_t n)
{
int i = 0;
hp->_capacity = 15;
hp->_size = 0;
hp->_a = (HeapDateType*)malloc(sizeof(HeapDateType)*hp->_capacity);
if (hp->_a == NULL)
return;
for (i = 0; i < (int)n; i++)
{
hp->_a[i] = a[i];
hp->_size++;
}
}
调整的原理:从最后一个非叶子结点开始调整,一直到根节点为止,将每个结点及其子 树调整到满足小堆的性质即可
1:假设该结点的下标为parent
2:找到该结点的左孩子left=parent*2+1
3:如果右孩子right=parent*2+1存在,找到left和right中最大的孩子
4:比较parent是否大于其左右孩子中的大者,如果parent大于较大者,调整结束。否则将parent中元素与较大的孩子交换,此时有可能导致子树不满足堆的性质,继续对其子树进行调整直到满足堆的性质。
void HeapMake(Heap* hp)//创建堆
{
int i;
for (i = (hp->_size - 2) / 2; i >= 0; i--)
{
HeapAdjustDown(hp,i);//调整函数
}
}
void HeapAdjustDown(Heap* hp, int root)
{
int parent = root;
int child;
child = 2 * parent + 1;
while (child<(int)hp->_size)//向下调整,直到不存在孩子
{
//选出来较大的孩子
if (child + 1 <(int) hp->_size&&hp->_a[child + 1] > hp->_a[child])
{
child++;
}
if (hp->_a[child] > hp->_a[parent])
{
HeapDateType tmp = hp->_a[child];//交换
hp->_a[child] = hp->_a[parent];
hp->_a[parent] = tmp;
parent = child;
child = parent * 2 + 1;
}
else
break;
}
}
堆的插入&删除 :
堆的插入:在已经建成的最大堆的后面插入新元素,插入之后,当树中结点不满足堆的性质时,就需要对堆从下往上进行调整
void HeapPush(Heap* hp, HeapDateType x)
{
if (hp->_size == hp->_capacity)
{
hp->_capacity *= 2;
hp->_a = (HeapDateType*)realloc(hp->_a, sizeof(HeapDateType)*hp->_capacity);
assert(hp->_a);
}
hp->_a[hp->_size] = x;
hp->_size++;
int child = (int)hp->_size - 1;
HeapAdjustUp(hp, child);
}
void HeapAdjustUp(Heap* hp, int child)
{
int parent = (child - 1) / 2;
while (parent >= 0)
{
if (hp->_a[child] > hp->_a[parent])
{
HeapDateType tmp = hp->_a[child];
hp->_a[child] = hp->_a[parent];
hp->_a[parent] = tmp;
child = parent;
parent = (child - 1) / 2;
}
else
break;
}
}
堆的删除:删除时每次删除堆顶元素
1:将堆中最后一个元素代替堆顶元素
2:将堆中元素个数减少一个,相当于将堆中最后一个元素删除
3:此时堆结构可能破坏,再向下调整使其满足堆的性质
void HeapPop(Heap* hp)
{
HeapDateType tmp = hp->_a[0];
hp->_a[0] = hp->_a[hp->_size - 1];
hp->_a[hp->_size - 1] = tmp;
hp->_size--;
HeapAdjustDown(hp, 0);
}
堆排序:
将堆的根节点取出(一般是与最后一个节点进行交换),将前面size-1个节点继续进行堆调整的过程,然后再将根节点取出,这样一直到所有节点都取出。
void HeapSort(Heap* hp)
{
size_t n = hp->_size;
while (Heapsize(hp) > 1)
{
HeapDateType tmp = hp->_a[0];
hp->_a[0] = hp->_a[hp->_size - 1];
hp->_a[hp->_size - 1] = tmp;
hp->_size--;
HeapAdjustDown(hp, 0);
}
hp->_size = n;
HeapPrint(hp);
}
代码及函数实现
#include<stdio.h>
#include<windows.h>
#include<malloc.h>
#include<assert.h>
typedef int HeapDateType;
typedef struct Heap
{
HeapDateType* _a;
size_t _size;
size_t _capacity;
}Heap;
void HeapInit(Heap* hp, HeapDateType* a, size_t n);//初始化
void HeapMake(Heap* hp);//创建堆
void HeapPush(Heap* hp, HeapDateType x);//堆的插入
void HeapPop(Heap* hp);//堆的删除
size_t HeapEmpty(Heap* hp);
size_t Heapsize(Heap* hp);
HeapDateType HeapTop(Heap* hp);
void HeapSort(Heap* hp);//堆排序
void HeapAdjustDown(Heap* hp, int root);
void HeapAdjustUp(Heap* hp, int child);
#include"Heap.h"
void HeapInit(Heap* hp, HeapDateType* a, size_t n)
{
int i = 0;
hp->_capacity = 15;
hp->_size = 0;
hp->_a = (HeapDateType*)malloc(sizeof(HeapDateType)*hp->_capacity);
if (hp->_a == NULL)
return;
for (i = 0; i < (int)n; i++)
{
hp->_a[i] = a[i];
hp->_size++;
}
}
void HeapPrint(Heap* hp)
{
int i = 0;
for (i = 0; i < (int)hp->_size; i++)
{
printf("%d ", hp->_a[i]);
}
printf("\n");
}
void HeapMake(Heap* hp)
{
int i;
for (i = (hp->_size - 2) / 2; i >= 0; i--)
{
HeapAdjustDown(hp,i);
}
}
void HeapAdjustDown(Heap* hp, int root)
{
int parent = root;
int child;
child = 2 * parent + 1;
while (child<(int)hp->_size)
{
if (child + 1 <(int) hp->_size&&hp->_a[child + 1] > hp->_a[child])
{
child++;
}
if (hp->_a[child] > hp->_a[parent])
{
HeapDateType tmp = hp->_a[child];
hp->_a[child] = hp->_a[parent];
hp->_a[parent] = tmp;
parent = child;
child = parent * 2 + 1;
}
else
break;
}
}
void HeapPush(Heap* hp, HeapDateType x)
{
if (hp->_size == hp->_capacity)
{
hp->_capacity *= 2;
hp->_a = (HeapDateType*)realloc(hp->_a, sizeof(HeapDateType)*hp->_capacity);
assert(hp->_a);
}
hp->_a[hp->_size] = x;
hp->_size++;
int child = (int)hp->_size - 1;
HeapAdjustUp(hp, child);
}
void HeapAdjustUp(Heap* hp, int child)
{
int parent = (child - 1) / 2;
while (parent >= 0)
{
if (hp->_a[child] > hp->_a[parent])
{
HeapDateType tmp = hp->_a[child];
hp->_a[child] = hp->_a[parent];
hp->_a[parent] = tmp;
child = parent;
parent = (child - 1) / 2;
}
else
break;
}
}
void HeapPop(Heap* hp)
{
HeapDateType tmp = hp->_a[0];
hp->_a[0] = hp->_a[hp->_size - 1];
hp->_a[hp->_size - 1] = tmp;
hp->_size--;
HeapAdjustDown(hp, 0);
}
size_t HeapEmpty(Heap* hp)
{
if (hp->_size == 0)
return 1;
else
return 0;
}
size_t Heapsize(Heap* hp)
{
return hp->_size;
}
HeapDateType HeapTop(Heap* hp)
{
return hp->_a[hp->_size];
}
void HeapSort(Heap* hp)
{
size_t n = hp->_size;
while (Heapsize(hp) > 1)
{
HeapDateType tmp = hp->_a[0];
hp->_a[0] = hp->_a[hp->_size - 1];
hp->_a[hp->_size - 1] = tmp;
hp->_size--;
HeapAdjustDown(hp, 0);
}
hp->_size = n;
HeapPrint(hp);
}
int main()
{
Heap hp;
HeapDateType a[]= { 53, 17, 78, 9, 45, 65, 87, 23, 31 };
size_t n = sizeof(a) / sizeof(a[0]);
HeapInit(&hp, a, n);
HeapPrint(&hp);
HeapMake(&hp);
HeapPrint(&hp);
HeapPush(&hp, 100);
HeapPrint(&hp);
HeapPop(&hp);
HeapPrint(&hp);
HeapSort(&hp);
system("pause");
return 0;
}
运行结果: