一.堆概念讲解
堆总是一颗完全二叉树(树,会在接下来的文章里讲解):这就导致了堆用顺序表更加好表示。
堆可以分为大堆与小堆。(与顺序表(可以看前几篇文章)相比,新加的两个算法是一个向上调整,与向下调整,除此之外并无其他。)
接下来是一个小堆的实现,堆的搭建是一个难点,这篇文章先不讲解,之间给push出一个堆。
二.代码实现部分
heap.h 头文件
#pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h> #include<stdbool.h> typedef int HPDataType; typedef struct Heap { HPDataType* _a; int _size; int _capacity; }Heap; // 堆的构建 void HeapInit(Heap* hp); // 堆的销毁 void HeapDestory(Heap* hp); // 堆的插入 void HeapPush(Heap* hp, HPDataType x); // 堆的删除 void HeapPop(Heap* hp); // 取堆顶的数据 HPDataType HeapTop(Heap* hp); // 堆的数据个数 int HeapSize(Heap* hp); // 堆的判空 bool HeapEmpty(Heap* hp);
heap.c 实现文件
#include"heap.h" // 堆的构建 void HeapInit(Heap* hp) { assert(hp); hp->_a = NULL; hp->_capacity = 0; hp->_size = 0; } // 堆的销毁 void HeapDestory(Heap* hp) { assert(hp); free(hp->_a); hp->_a = NULL; hp->_capacity = hp->_size = 0; } void Swap(HPDataType* x,HPDataType* y) { HPDataType tmp = *x; *x = *y; *y = tmp; } //向上调整 void AdjustUp(Heap* hp,int child) { int parent = (child -1) / 2; while (hp->_a[parent] > hp->_a[child]) { Swap(&hp->_a[parent], &hp->_a[child]); child = parent; parent = (child - 1) / 2; } } // 堆的插入 void HeapPush(Heap* hp, HPDataType x) { assert(hp); if (hp->_capacity == hp->_size) { int newCapacity = hp->_capacity == 0 ? 4:hp->_capacity * 2; HPDataType* tmp = (HPDataType*)realloc(hp->_a, sizeof(HPDataType) * newCapacity); if (tmp == NULL) { printf("realloc failed"); exit(-1); } hp->_a = tmp; hp->_capacity = newCapacity; } hp->_a[hp->_size] = x; hp->_size++; AdjustUp(hp,hp->_size-1); } //向下调整 void AdjustDown(Heap*hp,int parent) { int child = parent * 2 + 1; while ( child < hp->_size) { if (child + 1< hp->_size && hp->_a[child + 1] <hp->_a[child]) { child++; } if (hp->_a[child] < hp->_a[parent]) { Swap(&hp->_a[child], &hp->_a[parent]); parent = child; child = parent * 2 + 1; } else { break; } } } // 堆的删除 void HeapPop(Heap* hp) { assert(hp); assert(hp->_size > 0); Swap(&hp->_a[hp->_size - 1],&hp->_a[0]); hp->_size--; AdjustDown(hp, 0); } // 取堆顶的数据 HPDataType HeapTop(Heap* hp) { assert(hp); assert(hp->_size > 0); return hp->_a[0]; } // 堆的数据个数 int HeapSize(Heap* hp) { assert(hp); return hp->_size; } // 堆的判空 bool HeapEmpty(Heap* hp) { assert(hp); return hp->_size == 0; }
test.c 文件
#include<stdio.h> #include"heap.h" int main() { int a[] = { 4,6,2,1,5,8,2,9}; Heap hp; HeapInit(&hp); for (int i = 0; i < sizeof(a) / sizeof(int); ++i) { HeapPush(&hp, a[i]); } for (int i = 0; i < hp._size; ++i) { printf("%d ",hp._a[i]); } printf("\n"); int k = 3; while (k--) { printf("%d\n", HeapTop(&hp)); HeapPop(&hp); } while (!HeapEmpty(&hp)) { printf("%d ", HeapTop(&hp)); HeapPop(&hp); } printf("\n"); HeapDestory(&hp); return 0; }
三.算法的讲解(以 test.c 里面的例子举例) ,建立小堆
AdjustUp( ) //像上调整算法
AdjustDown( ) //向下调整算法
图有点丑,希望能帮助大家理解,下一篇文章会是二叉树的,以及堆的构建。