基础:
1. 堆是一个完全二叉树
2. 堆有两种, 一种叫小堆(小根堆, 最小堆),
一种叫大堆(大根堆, 最大堆).
3. 以小堆为例, 这个树的根节点是这个树中的最小的元素
对于任意一个子树来说, 子树的根节点, 小于左右孩子节点的值.
4. 以大堆为例, 这个树的根节点是这个树中的最大元素
对于任意一个子树来说, 子树的根节点, 大于左右孩子节点的值.
下面以小堆为例:
①heap.h
#pragma once
#include <stddef.h>
#define HeapMaxSize 1000
typedef int HeapType;
typedef int(*Compare)(HeapType a, HeapType b);
typedef struct Heap {
HeapType data[HeapMaxSize];
size_t size;
Compare cmp;
} Heap;
void HeapInit(Heap* heap, Compare compare); //初始化堆
void HeapPrintChar(Heap* heap, const char* msg);
void HeapInsert(Heap* heap, HeapType value); //插入元素
int HeapRoot(Heap* heap, HeapType* value); // 取堆顶元素
void HeapErase(Heap* heap); // 删除堆顶元素
int HeapEmpty(Heap* heap);
size_t Heapsize(Heap* heap);
void Heapdestroy(Heap* heap);
void HeapSort1(HeapType array[], size_t size); //堆排序
// 在我们不想开辟额外的空间, 或者消耗额外的时间的前提下,
// 如果我们想进行从小到大排序, 就需要一个大堆
// 如果我们想进行从大到小排序, 就需要一个小堆
void HeapSort2(HeapType array[], size_t size);
void HeapSort3(HeapType array[], size_t size);
void AdjustUp(HeapType data[], size_t size, Compare cmp, size_t index);
void AdjustDown(HeapType data[], size_t size, Compare cmp, size_t index);
②heap.c
#include "heap.h"
#include <stdio.h>
void HeapInit(Heap* heap, Compare compare) //初始化堆
{
if (heap == NULL || compare == NULL)
{
return; //非法输入
}
heap->size = 0;
heap->cmp = compare;
return;
}
void HeapPrintChar(Heap* heap, const char* msg)
{
printf("[%s]:", msg);
size_t i = 0;
for (; i < heap->size; ++i)
{
printf("[%lu]:%d ", i, heap->data[i]);
}
printf("\n");
}
void Swap(HeapType *a, HeapType *b)
{
HeapType tmp = *a;
*a = *b;
*b = tmp;
return;
}
void AdjustUp(HeapType data[], size_t size, Compare cmp, size_t index)
{
//1.先找到当前节点对应的父节点
if (index >= size)
{
return;
}
size_t child = index;
size_t parent = (child - 1) / 2;
//2.比较父节点与子节点的大小关系,
// 如果子节点的值比父节点的小,交换父子节点的值;如果子节点的值比父节点大,说明调整完成了
while (child > 0)
{
//3.将当前的父节点作为新的子节点,再去找子节点的父节点,循环进行比较和交换
//4.子节点下标为0,结束
if (cmp(data[child], data[parent]))
{
Swap(&data[child], &data[parent]);
}
else
{
break;
}
child = parent;
parent = (child - 1) / 2;
}
return;
}
void HeapInsert(Heap* heap, HeapType value) //插入元素
{
if (heap == NULL)
{
return; //非法输入
}
if (heap->size >= HeapMaxSize)
{
return; //堆已满
}
heap->data[heap->size++] = value;
AdjustUp(heap->data, heap->size, heap->cmp, heap->size - 1);
}
int HeapRoot(Heap* heap, HeapType* value) // 取堆顶元素
{
if (heap == NULL)
{
return 0; //非法输入
}
if (heap->size == 0)
{
return 0;
}
*value = heap->data[0];
return 1;
}
void AdjustDown(HeapType data[], size_t size, Compare cmp, size_t index)
{
//1.设定parent指向开始位置,找到对应的子节点
size_t parent = index;
//2.设定一个child指向parent的左子树
size_t child = 2 * parent + 1;
while (child < size)
{
//3.判定child和child+1的大小关系
// 如果child+1的值比child的值小,就让child=child+1
if (child+1 < size && cmp(data[child + 1], data[child]))
{
child = child + 1;
}
//4.判定parent和child的大小关系
// 如果parent的值比child的值大,就需要进行交换,否则说明调整已完成
if (cmp(data[child], data[parent]))
{
Swap(&data[child], &data[parent]);
}
else
{
break;
}
//5.parent赋值成child,child再重新赋值成parent的左孩子节点
parent = child;
child = 2 * parent + 1;
}
return;
}
void HeapErase(Heap* heap) // 删除堆顶元素
{
if (heap == NULL)
{
return; //非法输入
}
if (heap->size == 0)
{
return;
}
Swap(&heap->data[0], &heap->data[heap->size - 1]);
--heap->size;
AdjustDown(heap->data, heap->size, heap->cmp, 0);
}
int HeapEmpty(Heap* heap)
{
if (heap == NULL)
{
return 0; //非法输入
}
return heap->size == 0 ? 1 : 0;
}
size_t Heapsize(Heap* heap)
{
if (heap == NULL)
{
return 0; //非法输入
}
return heap->size;
}
void Heapdestroy(Heap* heap)
{
if (heap == NULL)
{
return; //非法输入
}
heap->size = 0;
return;
}
③test.c
#include "heap.h"
#include <stdio.h>
#include <windows.h>
#define TEST_HEADER printf("\n=============================%s============================\n",__FUNCTION__)
int Less(HeapType a, HeapType b)
{
return a < b;
}
int More(HeapType a, HeapType b)
{
return a > b;
}
void HeapSort1(HeapType array[], size_t size) //堆排序
{
Heap heap;
HeapInit(&heap, Less);
//1.先将数组中的所有元素都插入到堆中
size_t i = 0;
for (; i < size; ++i)
{
HeapInsert(&heap, array[i]);
}
//2.依次取堆顶元素,放回到原数组,并删除堆顶元素
size_t index = 0;
while (!HeapEmpty(&heap))
{
HeapType root = 0;
HeapRoot(&heap, &root);
array[index++] = root;
HeapErase(&heap);
}
return;
}
void HeapSort2(HeapType array[], size_t size)
{
//1.直接在数组的前提下生成一个堆,循环结束后形成一个小堆
//2.依次取堆顶元素并进行删除
if (size == 0 || size == 1)
{
return;
}
size_t heap_size = 0;
for (; heap_size < size; ++heap_size)
{
AdjustUp(array, heap_size, More, heap_size - 1);
//AdjustUp(array, heap_size, Less, heap_size - 1);
}
while (heap_size>0)
{
Swap(&array[0], &array[heap_size - 1]);
--heap_size;
AdjustDown(array, heap_size, More, 0);
//AdjustDown(array, heap_size, Less, 0);
}
return;
}
void HeapSort3(HeapType array[], size_t size)
{
if (size == 0 || size == 1)
{
return;
}
//若采用下沉建立堆,需从后往前遍历数组,取任意一个元素之后,找到该元素的左右孩子节点
size_t end = (size - 1 - 1) / 2;
for (; end > 0; --end)
{
AdjustDown(array, size, More, end - 1);
//AdjustDown(array, size, Less, end - 1);
}
size_t heap_size = size;
while (heap_size > 0)
{
Swap(&array[0], &array[heap_size - 1]);
--heap_size;
AdjustDown(array, heap_size, More, 0);
//AdjustDown(array, heap_size, Less, 0);
}
return;
}
以下是测试函数
void TestInit()
{
TEST_HEADER;
Heap heap;
HeapInit(&heap, Less);
printf("heap->size expect 0,actual %lu\n", heap.size);
printf("heap->cmp expect %p,actual %p\n", Less, heap.cmp);
}
void TestInsert()
{
TEST_HEADER;
Heap heap;
HeapInit(&heap, Less);
HeapInsert(&heap, 9);
HeapInsert(&heap, 5);
HeapInsert(&heap, 23);
HeapInsert(&heap, 17);
HeapInsert(&heap, 2);
HeapPrintChar(&heap, "插入5个元素");
}
void TestRoot()
{
TEST_HEADER;
Heap heap;
HeapInit(&heap, Less);
HeapInsert(&heap, 9);
HeapInsert(&heap, 5);
HeapInsert(&heap, 23);
HeapInsert(&heap, 17);
HeapInsert(&heap, 2);
HeapPrintChar(&heap, "插入5个元素");
HeapType value = 0;
int ret = HeapRoot(&heap, &value);
printf("ret expect 1,actual %d\n", ret);
printf("value expect 2,actual %d\n", value);
}
void TestErase()
{
TEST_HEADER;
Heap heap;
HeapInit(&heap, Less);
HeapInsert(&heap, 9);
HeapInsert(&heap, 5);
HeapInsert(&heap, 23);
HeapInsert(&heap, 17);
HeapInsert(&heap, 2);
HeapPrintChar(&heap, "插入5个元素");
HeapErase(&heap);
HeapPrintChar(&heap, "删除堆顶元素之后");
}
void TestEmpty()
{
TEST_HEADER;
Heap heap;
HeapInit(&heap, Less);
int ret = HeapEmpty(&heap);
printf("ret expect 1,actual %d\n", ret);
HeapInsert(&heap, 9);
HeapInsert(&heap, 5);
HeapInsert(&heap, 23);
HeapInsert(&heap, 17);
HeapInsert(&heap, 2);
HeapPrintChar(&heap, "插入5个元素");
ret = HeapEmpty(&heap);
printf("ret expect 0,actual %d\n", ret);
}
void TestSize()
{
TEST_HEADER;
Heap heap;
HeapInit(&heap, Less);
size_t ret = Heapsize(&heap);
printf("ret expect 0,actual %d\n", ret);
HeapInsert(&heap, 9);
HeapInsert(&heap, 5);
HeapInsert(&heap, 23);
HeapInsert(&heap, 17);
HeapInsert(&heap, 2);
HeapPrintChar(&heap, "插入5个元素");
ret = Heapsize(&heap);
printf("ret expect 5,actual %d\n", ret);
}
void TestDestroy()
{
TEST_HEADER;
Heap heap;
HeapInit(&heap, Less);
HeapInsert(&heap, 9);
HeapInsert(&heap, 5);
HeapInsert(&heap, 23);
HeapInsert(&heap, 17);
HeapInsert(&heap, 2);
HeapPrintChar(&heap, "插入5个元素");
printf("heap->size expect 5,actual %lu\n", heap.size);
Heapdestroy(&heap);
HeapPrintChar(&heap, "销毁后");
printf("heap->size expect 0,actual %lu\n", heap.size);
}
void TestSort1()
{
TEST_HEADER;
int array[] = { 8, 6, 12, 18, 25, 1, 14, 9 };
int len = sizeof(array) / sizeof(array[0]);
printf("[排序前]:");
size_t i = 0;
for (; i < len; ++i)
{
printf("%d ", array[i]);
}
printf("\n");
HeapSort1(array, len);
printf("[排序后]:");
for (i = 0; i < len; ++i)
{
printf("%d ", array[i]);
}
printf("\n");
}
void TestSort2()
{
TEST_HEADER;
int array[] = { 8, 6, 12, 18, 25, 1, 14, 9 };
int len = sizeof(array) / sizeof(array[0]);
printf("[排序前]:");
size_t i = 0;
for (; i < len; ++i)
{
printf("%d ", array[i]);
}
printf("\n");
HeapSort2(array, len);
printf("[排序后]:");
for (i = 0; i < len; ++i)
{
printf("%d ", array[i]);
}
printf("\n");
}
void TestSort3()
{
TEST_HEADER;
int array[] = { 8, 6, 12, 18, 25, 1, 14, 9 };
int len = sizeof(array) / sizeof(array[0]);
printf("[排序前]:");
size_t i = 0;
for (; i < len; ++i)
{
printf("%d ", array[i]);
}
printf("\n");
HeapSort3(array, len);
printf("[排序后]:");
for (i = 0; i < len; ++i)
{
printf("%d ", array[i]);
}
printf("\n");
}
int main()
{
TestInit();
TestInsert();
TestRoot();
TestErase();
TestEmpty();
TestSize();
TestDestroy();
TestSort1();
TestSort2();
TestSort3();
system("pause");
return 0;
}
④测试结果