堆是一个完全二叉树;
它的底层就是一个一维数组;
它的形式还是一个二叉树;
堆的特点的总结:
大堆和小堆的特点就是 我们的父亲和孩子的大小的关系;
大堆: 就是我们的父亲是不小于孩子;
小堆:就是我们的父亲是不大于孩子;
下标的关系:
左孩子的下标
child = parent * 2 + 1
右孩子的下标就是左孩子加1;
结构体的成员:
我们知道底层是一个数组,那我们自然会想到顺序表的成员;
没错我们堆的成员和顺序表的成员是完全一样的;
typedef int HPDataType;
typedef struct Heap
{
HPDataType* a;
int size;
int capacity;
}Heap;
功能代码的实现:
插入元素:
我们是按照顺序表的结构来作为底层的;所以我们直接尾插;因为尾插效率比头插效率高多了;
但是我们要保证堆结构的特点,所以我们必须调整我们尾部插入的元素;所以我们要实现一个向上调整的函数
// 堆的插入
void HeapPush(Heap* php, HPDataType x) {
assert(php);
if (php->capacity == php->size) {
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;
AdjustUp(php->a, php->size);
php->size++;
}
向上调整:
我们先建立一个大堆;
我们堆的插入都是先尾插;因为我们底层是数组,所以我们在根据堆的特点来进行调整;
那我们先实现大堆的向上调整;就是当我们父亲小于孩子的时候我们进行调整;
我们知道要处理的元素的位置,在我们的最后;那我们怎么找到他的父亲呢?
,这个公式不用记忆,直接推导;因为我的整数会趋零截断;所以我们的左孩子和右孩子带人公式会指向同一个位置;
那我们怎么找到我们结束的条件呢?
(1)我们可以在我们的要调整的元素小于父亲的时候,就结束;
这个好实现直接遇见了就跳出循环;
(2)我们调整到了堆顶就结束;
我们怎么知道到堆顶了? 我们的底层是一个数组呀,所以我们堆顶就是我们的数组的下标为0的位置;
这样我们就可以写代码了;
//向上调整
void AdjustUp(HPDataType* a, int child) {
assert(a);
while (child > 0) {
int parent = (child - 1) / 2;
if (a[parent] < a[child]) {
swap(&a[parent], &a[child]);
child = parent;
}
else {
break;
}
}
}
堆的删除:
我们是按照顺序表的结构来作为底层的;所以我们直接尾删;因为尾删效率比头插效率高多了;
我们就直接交换头尾的元素,然后将size减1,就是顺序表的删除了;
但是我们要保证堆结构的特点,所以我们必须调整我们头部的元素;所以我们要实现一个向下调整的函数
// 堆的删除
void HeapPop(Heap* php) {
assert(php && php->size);
swap(&(php->a[0]), &(php->a[php->size - 1]));
php->size--;
if(php->size>0) AdjustDown(php->a, php->size, 0);
}
向下调整:
我们是要实现一个大堆,所以我们要比较头部节点和孩子中最小的的大小;如果我们比孩子中最小的还小;我们将进行调整;但是我们知道堆是一个完全二叉树,所以我们肯定是先有左孩子,右孩子是否存在不一定;怎么快速确认呢?很简单,利用他是完全二叉树的特点,只要他的右孩子后面还有节点,那他的右孩子一定存在;最简单的判断方法就是看他的右孩子的位置是否在数组大小里面;
那我们的循环结束条件呢?
(1)要调整的节点到了最底层,我们判断的方法就是他没有孩子,根据底层来说,就是他孩子的下标超过了数组的大小;
这个就是
parent*2+1<size
就是循环条件;(2)要调整的节点并不小于最小的孩子了;
这个就是
MIN>=parent
//向下调整
void AdjustDown(HPDataType* a, int size, int parent) {
while (parent *2+1 < size) {
int child = parent * 2 + 1;
int rightChild = child + 1;
int minIndex = child;
if (rightChild < size && a[rightChild] < a[child]) {
minIndex = rightChild;
}
if (a[parent] > a[minIndex]) {
swap(&a[parent], &a[minIndex]);
parent = minIndex;
}
else {
break;
}
}
}
总的大堆的代码:
#pragma once
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
typedef int HPDataType;
typedef struct Heap
{
HPDataType* a;
int size;
int capacity;
}Heap;
//按照数组进行打印
void Print(Heap* php);
//交换函数
void swap(HPDataType* a, HPDataType* b);
//堆的初始化
void HeapInit(Heap* php);
// 堆的销毁
void HeapDestory(Heap* php);
//向上调整
void AdjustUp(HPDataType* a, int child);
// 堆的插入
void HeapPush(Heap* php, HPDataType x);
//向下调整
void AdjustDown(HPDataType* a, int size, int parent);
// 堆的删除
void HeapPop(Heap* php);
// 取堆顶的数据
HPDataType HeapTop(Heap* php);
// 堆的数据个数
int HeapSize(Heap* php);
// 堆的判空
bool HeapEmpty(Heap* php);
#include"Heap.h"
//交换函数
void swap(HPDataType* a, HPDataType* b) {
int tmp = *a;
*a = *b;
*b = tmp;
}
//堆的初始化
void HeapInit(Heap* php) {
assert(php);
php->a = NULL;
php->capacity = php->size = 0;
}
// 堆的销毁
void HeapDestory(Heap* php) {
assert(php);
free(php->a);
php->a = NULL;
php->capacity = php->size = 0;
}
//向上调整
void AdjustUp(HPDataType* a, int child) {
assert(a);
while (child > 0) {
int parent = (child - 1) / 2;
if (a[parent] < a[child]) {
swap(&a[parent], &a[child]);
child = parent;
}
else {
break;
}
}
}
// 堆的插入
void HeapPush(Heap* php, HPDataType x) {
assert(php);
if (php->capacity == php->size) {
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;
AdjustUp(php->a, php->size);
php->size++;
}
//按照数组进行打印
void Print(Heap* php) {
assert(php);
int i = 0;
while (i < php->size) {
printf("%d", php->a[i++]);
}
printf("\n");
}
//向下调整
void AdjustDown(HPDataType* a, int size, int parent) {
while (parent *2+1 < size) {
int child = parent * 2 + 1;
int rightChild = child + 1;
int minIndex = child;
if (rightChild < size && a[rightChild] < a[child]) {
minIndex = rightChild;
}
if (a[parent] > a[minIndex]) {
swap(&a[parent], &a[minIndex]);
parent = minIndex;
}
else {
break;
}
}
}
// 堆的删除
void HeapPop(Heap* php) {
assert(php && php->size);
swap(&(php->a[0]), &(php->a[php->size - 1]));
php->size--;
if(php->size>0) AdjustDown(php->a, php->size, 0);
}
// 取堆顶的数据
HPDataType HeapTop(Heap* php) {
assert(php && php->size);
return php->a[0];
}
// 堆的数据个数
int HeapSize(Heap* php) {
assert(php);
return php->size;
}
// 堆的判空
bool HeapEmpty(Heap* php) {
assert(php);
return php->size==0;
}