文章目录
- 1.堆的概念及结构
- 2.堆的实现
- 2.1父子节点之间的关系
- 2.2堆的向上排序算法
- 2.3 堆的删除
- 2.4堆的向下排序算法
- 2.5入堆
- 2.6堆的创建
- 2.6.1通过入堆实现(通过向上堆排序)
- 2.6.2通过向下排序实现
- 2.6.3两种方法比较
- 2.7代码实现
- 2.7.1函数声明
- 2.7.2函数实现
- 2.7.3代码测试
1.堆的概念及结构
如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足: <= 且 <= ( >= 且 >= ) i = 0,1,2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的性质:
堆中某个节点的值总是不大于或不小于其父节点的值;
堆总是一棵完全二叉树。
2.堆的实现
2.1父子节点之间的关系
在此之前,我们先了解一下父子节点之间的关系
leftchild=parent2+1
rightchild=parent2+2
parent=(chile-1)/2
2.2堆的向上排序算法
正如图上所示,我们插入一个80节点,显然它比它的祖先都要大,所以我们要调整堆这就用到了向上调整法
思路就是这样 代码如下:
void AdjustUp(HPDataType* a, int child)
{
int parent = (child - 1) / 2;//定义父节点
while (child > 0)//这里的判定条件可以有另外一种为parent>=0,
虽然也可以实现函数但是当child=0时,parent=(0-1)/2=0,
if语句不成立才break的,是非正常结束,所以不推荐
{
if (a[parent] < a[child])
{
Swap(&a[parent], &a[child]);//交换位置
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
2.3 堆的删除
删除堆是删除堆顶的数据,将堆顶的数据根最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。
void HeapPop(HP* php)
{
assert(php);
assert(php->size > 0);
Swap(&php->a[php->size - 1], &php->a[0]);
php->size--;
AdjustDown(php->a, php->size, 0);
}
2.4堆的向下排序算法
void AdjustDown(HPDataType* a, int n, int parent)
{
int child = 2 * parent + 1;
while (child < n)
{
if (child + 1 < n && a[child + 1] > a[child])
{
child++;
}
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = 2 * parent + 1;
}
else
break;
}
}
2.5入堆
void Heappush(HP* php, HPDataType x)
{
assert(php);
if (php->size == php->capacity)
{
int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
php->a = tmp;
php->capacity = newcapacity;
}
php->a[php->size] = x;
php->size++;
AdjustUp(php->a, php->size - 1);
}
2.6堆的创建
2.6.1通过入堆实现(通过向上堆排序)
这种方法也是比较投机取巧的方法了
// 堆的构建
void HeapCreate(HP* php, HPDataType* a, int n)
{
assert(php);
HeapInit(php);
for (int i = 0; i < n; ++i)
{
HeapPush(php, a[i]);
}
}
这种方法的时间复杂度
2.6.2通过向下排序实现
void HeapCreate(HP* php, HPDataType* a, int n)
{
assert(php);
php->a = (HPDataType*)malloc(php->a, sizeof(HPDataType)*n);
if (php->a == NULL)
{
perror("realloc fail");
exit(-1);
}
memcpy(php->a, a, sizeof(HPDataType)*n);
php->size = php->capacity = n;
// 建堆算法
for (int i = (n-1-1)/2; i>=0; --i)
{
AdjustDown(a, n, i);
}
}
这种方法时间复杂度
2.6.3两种方法比较
两种方法比较来说
通过向下排序实现的创建堆方便太多了
2.7代码实现
2.7.1函数声明
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
#include<string.h>
typedef int HPDataType;
typedef struct Heap
{
HPDataType* a;
int size;
int capacity;
}HP;
void HeapInit(HP* php);
void HeapDestory(HP* php);
void Heappush(HP* php, HPDataType x);
void HeapPop(HP* php);
HPDataType HeapTop(HP* php);
bool HeapEmpty(HP* php);
void HeapPrint(HP* php);
void HeapCreate(HP* php, HPDataType* a, int n);
void AdjustDown(HPDataType* a, int n, int parent);
void Swap(HPDataType* p1, HPDataType* p2);
void AdjustUp(HPDataType* a, int child);
2.7.2函数实现
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
void HeapCreate(HP* php, HPDataType* a, int n)
{
assert(php);
php->a = (HPDataType*)malloc( sizeof(HPDataType) * n);
if (php->a == NULL)
{
perror("realloc fail");
exit(-1);
}
memcpy(php->a, a, sizeof(HPDataType) * n);
php->size = php->capacity = n;
// 建堆算法
for (int i = (n - 1 - 1) / 2; i >= 0; --i)
{
AdjustDown(php->a, n, i);
}
}
//void HeapCreate(HP* php, HPDataType* a, int n)
//{
// assert(php);
// HeapInit(php);
// for (int i = 0; i < n; ++i)
// {
// Heappush(php, a[i]);
// }
//}
void HeapInit(HP* php)
{
assert(php);
php->a = NULL;
php->size = php->capacity = 0;
}
void HeapDestory(HP* php)
{
assert(php);
free(php->a);
php->a = NULL;
php->capacity = php->size = 0;
}
void Swap(HPDataType* p1, HPDataType* p2)
{
HPDataType tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
void AdjustUp(HPDataType* a, int child)
{
int parent = (child - 1) / 2;
while (child > 0)
{
if (a[parent] < a[child])
{
Swap(&a[parent], &a[child]);
child = parent;
parent = (child - 1) / 2;
}
else
{
break;
}
}
}
void Heappush(HP* php, HPDataType x)
{
assert(php);
if (php->size == php->capacity)
{
int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;
HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);
if (tmp == NULL)
{
perror("realloc fail");
exit(-1);
}
php->a = tmp;
php->capacity = newcapacity;
}
php->a[php->size] = x;
php->size++;
AdjustUp(php->a, php->size - 1);
}
void AdjustDown(HPDataType* a, int n, int parent)
{
int child = 2 * parent + 1;
while (child < n)
{
if (child + 1 < n && a[child + 1] > a[child])
{
child++;
}
if (a[child] > a[parent])
{
Swap(&a[child], &a[parent]);
parent = child;
child = 2 * parent + 1;
}
else
break;
}
}
void HeapPop(HP* php)
{
assert(php);
assert(php->size > 0);
Swap(&php->a[php->size - 1], &php->a[0]);
php->size--;
AdjustDown(php->a, php->size, 0);
}
HPDataType HeapTop(HP* php)
{
assert(php);
assert(php->size > 0);
return php->a[0];
}
bool HeapEmpty(HP* php)
{
assert(php);
return php->size == 0;
}
void HeapPrint(HP* php)
{
assert(php);
for (int i = 0; i < php->size; ++i)
{
printf("%d ", php->a[i]);
}
printf("\n");
}
2.7.3代码测试
#define _CRT_SECURE_NO_WARNINGS 1
#include"Heap.h"
void test()
{
int array[] = { 27, 15, 19, 18, 28, 34, 65, 49, 25, 37 };
HP hp;
HeapInit(&hp);
HeapCreate(&hp, array, 10);
HeapPrint(&hp);
}
int main()
{
test();
}