赞
踩
上图中左侧是一个普通的二叉树,右侧是一个完全二叉树(也可称之为满二叉树),当使用顺序结构进行存储时,可以发现作图的存储存在着大量的空间浪费,而右侧的完全二叉树却没有浪费很多空间。
有关一维数组中如何寻找父子结点所在位置及其位置之间的关系,回看:
链接: 数据结构—二叉树相关概念【详解】【画图演示】
有关树中结点之间的关系及其概念,回看:
链接: 【树】简要理解树的概念
具体代码实现如下所示:
void AdjustUp(HPDataType* a, int child)
{
int 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 AdjustDown(HPDataType* a, int size, int parent) { int child = parent * 2 + 1; while (child < size) { if (child + 1 < size && a[child + 1] > a[child])//child + 1 < size 是为了避免子结点越界 { ++child; } if (a[child] > a[parent]) { Swap(&a[child], &a[parent]); parent = child; child = parent * 2 + 1; } else { break; } } }
typedef int HPDataType;
typedef struct Heap
{
HPDataType* a;
int size;
int capacity;
}HP;
void HPPush(HP* php, HPDataType x);
因堆顺序结构的定义如上,且其中代表数组的是一个指向数据类型的指针,故我们需要进行数组的空间开辟,故出现了如下代码:
if (php->size == php->capacity)
{
int newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;
HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity);
if (tmp == NULL)
{
perror("HPPush:realloc fail");
return;
}
php->a = tmp;
php->capacity = newcapacity;
}
上图代码中我们需要先判断数组中的空间是否足够,即php->size == php->capacity,若判断条件成立,则进入扩容阶段,一般在扩容时我们会进行原有数组空间大小的二倍扩容,这一依据是根据相关研究者的研究所得出的结论,并应用realloc对原数组进行扩容。
void HPPush(HP* php, HPDataType x) { assert(php); if (php->size == php->capacity) { int newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity; HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity); if (tmp == NULL) { perror("HPPush:realloc fail"); return; } php->a = tmp; php->capacity = newcapacity; } php->a[php->size] = x; php->size++; AdjustUp(php->a, php->size - 1); }
上述代码块中再插入数据后进行了向上调整,令所插入的数据形成大堆或小堆,以便后续使用。
向上调整代码及原理回看3.1.1向上调整 。
void HPPop(HP* php)
{
assert(php);
assert(php->size > 1);
Swap(&php->a[0], &php->a[php->size - 1]);
php->size--;
AdjustDown(php->a, php->size, 0);
}
向下调整代码及原理回看3.1.2向下调整 。
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <assert.h> typedef int HPDataType; typedef struct Heap { HPDataType* a; int size; int capacity; }HP; void Swap(HPDataType* p1, HPDataType* p2); void HPInit(HP* php); void HPDestroy(HP* php); void AdjustUp(HPDataType* a, int child); void HPPush(HP* php, HPDataType x); void AdjustDown(HPDataType* a, int size, int parent); void HPPop(HP* php); HPDataType HPTop(HP* php); bool HPEmpty(HP* php); int HPSize(HP* php);
#include "Heap.h" void Swap(HPDataType* p1, HPDataType* p2) { HPDataType tmp = *p1; *p1 = *p2; *p2 = tmp; } void HPInit(HP* php) { assert(php); php->a = NULL; php->size = php->capacity = 0; } void HPDestroy(HP* php) { assert(php); free(php->a); php->a = NULL; php->size = php->capacity = 0; } void AdjustUp(HPDataType* a, int child) { int 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 HPPush(HP* php, HPDataType x) { assert(php); if (php->size == php->capacity) { int newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity; HPDataType* tmp = (HPDataType*)realloc(php->a, sizeof(HPDataType) * newcapacity); if (tmp == NULL) { perror("HPPush:realloc fail"); return; } php->a = tmp; php->capacity = newcapacity; } php->a[php->size] = x; php->size++; AdjustUp(php->a, php->size - 1); } void AdjustDown(HPDataType* a, int size, int parent) { int child = parent * 2 + 1; while (child < size) { if (child + 1 < size && a[child + 1] > a[child]) { ++child; } if (a[child] > a[parent]) { Swap(&a[child], &a[parent]); parent = child; child = parent * 2 + 1; } else { break; } } } void HPPop(HP* php) { assert(php); assert(php->size > 1); Swap(&php->a[0], &php->a[php->size - 1]); php->size--; AdjustDown(php->a, php->size, 0); } HPDataType HPTop(HP* php) { assert(php); assert(php->size > 0); return php->a[0]; } bool HPEmpty(HP* php) { assert(php); return php->size == 0; } int HPSize(HP* php) { assert(php); return php->size; }
#include "Heap.h" void test() { HP s; HPInit(&s); HPPush(&s, 123); HPPush(&s, 12); HPPush(&s, 1); HPPush(&s, 321); HPPush(&s, 32); HPPush(&s, 3); printf("输入数据为:123,12,1,321,32,3\n"); printf("插入数据后数组内成员展示:"); for (int i = 0; i < s.size; i++) { printf("%d ", s.a[i]); } printf("\n"); HPPop(&s); HPPop(&s); printf("删除数据后数组内成员展示:"); for (int i = 0; i < s.size; i++) { printf("%d ", s.a[i]); } printf("\n"); printf("此时调用判空函数后结果展示:"); if (HPEmpty(&s)) printf("yes\n"); else printf("no\n"); printf("此时数组内成员个数:"); printf("%d\n", HPSize(&s)); printf("此时根节点的数据为:"); printf("%d\n", HPTop(&s)); } int main() { test(); return 0; }
链接: 图解堆排序【一眼看穿逻辑思路】
十分感谢您观看我的原创文章。
本文主要用于个人学习和知识分享,学习路漫漫,如有错误,感谢指正。
如需引用,注明地址。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。