1.堆得概念
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
2.堆向下调整算法
一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。向下调整算法有一个前提:左右子树必须是一个堆,才能调整。
3.堆的创建
一个数组,这个数组逻辑上可以看做一颗完全二叉树,但是还不是一个堆,现在我们通过算法,把它构建成一个堆。根节点左右子树不是堆,怎么调整呢?这里我们从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。
4. 堆的插入
先插入一个数到数组的尾上,再进行向上调整算法,直到满足堆.
5. 堆的删除
删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。`
6.堆排序
#pragma once
typedef int HPDataType;
typedef int (*PCOM)(HPDataType, HPDataType);
int Less(HPDataType left, HPDataType right);
int Greater(HPDataType left, HPDataType right);
typedef struct Heap
{
HPDataType* _array;
int _capacity;
int _size;
PCOM Compare;
}Heap;
void InitHeap(Heap* hp, HPDataType* array, int size, PCOM compare);
void InitEmptyHeap(Heap* hp, int capacity, PCOM compare);
void InsertHeap(Heap* hp, HPDataType data);
void EraseHeap(Heap* hp);
int HeapSize(Heap* hp);
int HeapEmpty(Heap* hp);
HPDataType HeapTop(Heap* hp);
void DestroyHeap(Heap* hp);
void TestHeap();
void HeapSort(int* array, int size);
#include "Heap.h"
#include <assert.h>
#include <malloc.h>
#include <stdio.h>
void Swap(HPDataType* pLeft, HPDataType* pRight)
{
HPDataType temp = *pLeft;
*pLeft = *pRight;
*pRight = temp;
}
//向下调整算法
void AdjustDown(HPDataType* array, int size, int parent, PCOM Compare)
{
// 默认让child标记parent的左孩子,因为:完全二叉树某个节点如果只有一个孩子,该孩子一定是其双亲的左孩子
int child = parent * 2 + 1;
while (child < size)
{
// 找双亲孩子中较小的孩子
if (child + 1 < size && Compare(array[child + 1], array[child]))
{
child += 1;
}
if (Compare(array[child],array[parent]))
{
Swap(&array[child], &array[parent]);
parent = child;
child = parent * 2 + 1;
}
else
return;
}
}
//向上调整算法
void AdjustUP(HPDataType* array, int size, int child, PCOM Compare)
{
int parent = (child - 1) / 2;
while (child)
{
if (Compare(array[child], array[parent]))
{
Swap(&array[child], &array[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
return;
}
}
void CheckCapacity(Heap* hp)
{
assert(hp);
if (hp->_size == hp->_capacity)
{
int newCapacity = hp->_capacity * 2;
// 申请新空间
HPDataType* pTemp = (HPDataType*)malloc(sizeof(HPDataType)*newCapacity);
if (NULL == pTemp)
{
assert(0);
return;
}
// 拷贝元素
for (int i = 0; i < hp->_size; ++i)
pTemp[i] = hp->_array[i];
// 释放旧空间
free(hp->_array);
hp->_array = pTemp;
hp->_capacity = newCapacity;
}
}
int Less(HPDataType left, HPDataType right)
{
return left < right;
}
int Greater(HPDataType left, HPDataType right)
{
return left > right;
}
void InitHeap(Heap* hp, HPDataType* array, int size, PCOM compare)
{
assert(hp);
hp->_array = (HPDataType*)malloc(sizeof(HPDataType)*size);
if (NULL == hp->_array)
{
assert(0);
return;
}
hp->_capacity = size;
for (int i = 0; i < size; ++i)
hp->_array[i] = array[i];
hp->_size = size;
hp->Compare = compare;
// 将该完全二叉树调整让其满足堆的性质
// 找完全二叉数中倒数第一个非叶子节点
int root = ((size - 2) >> 1);
for (; root >= 0; --root)
AdjustDown(hp->_array, size, root, hp->Compare);
}
void InitEmptyHeap(Heap* hp, int capacity, PCOM compare)
{
assert(hp);
hp->_array = (HPDataType*)malloc(sizeof(HPDataType)*capacity);
if (NULL == hp->_array)
{
assert(0);
return;
}
hp->_capacity = capacity;
hp->_size = 0;
hp->Compare = compare;
}
void InsertHeap(Heap* hp, HPDataType data)
{
CheckCapacity(hp);
hp->_array[hp->_size] = data;
hp->_size++;
AdjustUP(hp->_array, hp->_size, hp->_size - 1, hp->Compare);
}
void EraseHeap(Heap* hp)
{
if (HeapEmpty(hp))
return;
Swap(&hp->_array[0], &hp->_array[hp->_size - 1]);
hp->_size -= 1;
AdjustDown(hp->_array, hp->_size, 0, hp->Compare);
}
int HeapSize(Heap* hp)
{
assert(hp);
return hp->_size;
}
int HeapEmpty(Heap* hp)
{
assert(hp);
return 0 == hp->_size;
}
HPDataType HeapTop(Heap* hp)
{
assert(hp);
return hp->_array[0];
}
void DestroyHeap(Heap* hp)
{
assert(hp);
if (hp->_array)
{
free(hp->_array);
hp->_capacity = 0;
hp->_size = 0;
}
}
void TestHeap1()
{
Heap hp;
int array[] = {2,3,8,0,9,1,7,4,6,5};
InitHeap(&hp, array, sizeof(array) / sizeof(array[0]), Less);
printf("%d\n", HeapSize(&hp));
printf("%d\n", HeapTop(&hp));
EraseHeap(&hp);
printf("%d\n", HeapTop(&hp));
InsertHeap(&hp, 0);
printf("%d\n", HeapTop(&hp));
DestroyHeap(&hp);
}
void TestHeap2()
{
Heap hp;
InitEmptyHeap(&hp, 10, Greater);
int array[] = { 2, 3, 8, 0, 9, 1, 7, 4, 6, 5 };
for (int i = 0; i < 10; ++i)
InsertHeap(&hp, array[i]);
printf("%d\n", HeapSize(&hp));
printf("%d\n", HeapTop(&hp));
DestroyHeap(&hp);
}
void HeapAdjust(int* array, int size, int parent)
{
int child = parent * 2 + 1;
while (child < size)
{
// 找左右孩子中较大的孩子
if (child + 1 < size && array[child + 1] > array[child])
child += 1;
if (array[child] > array[parent])
{
Swap(&array[child], &array[parent]);
parent = child;
child = parent * 2 + 1;
}
else
{
return;
}
}
}
//堆排序
void HeapSort(int* array, int size)
{
// 1. 建堆---大堆,小堆?
// 找倒数第一个非叶子节点
int root = ((size - 2) >> 1);
for (; root >= 0; --root)
HeapAdjust(array, size, root);
// 2. 排序: 删除方式
int end = size - 1;
while (end)
{
Swap(&array[0], &array[end]);
HeapAdjust(array, end, 0);
end--;
}
}
void TestHeap()
{
//TestHeap1();
//TestHeap2();
int array[] = { 2, 3, 8, 0, 9, 1, 7, 4, 6, 5 };
HeapSort(array, sizeof(array)/sizeof(array[0]));
}