数据结构|【数据结构初阶】大堆与小堆的实现(向上向下调整)TopK问题


大堆与小堆的实现(向上向下调整)TopK问题

  • 什么是大堆,小堆
    • 堆的实现
      • TOPK问题

什么是大堆,小堆 定义:
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足:Ki <= K2i+1 且 Ki<= K2i+2 (Ki >= K2i+1 且 Ki >= K2i+2) i = 0,1,2…,则称为 小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆的实现
typedef struct Heap { HPDataType* _a; int _size; int _capacity; }Heap;

对数组进行堆排序:
向下排序(升序:小堆)
void HeapDown(Heap* hp, int n, int root); { int parent = *hp; int child = parent * 2 + 1; while (child < n) { if (child+1&&child+1

图例:
数据结构|【数据结构初阶】大堆与小堆的实现(向上向下调整)TopK问题
文章图片

向上调整算法(大堆:降序)
将想要比较的child传进来然后通过特性算出parent和向下一样进行比较区别在于如果child比parent大就进行交换将将较大的数传入上方。
void HeapUp(Heap* hp,int n,int child) { HPDataType* parent = (child - 1) / 2; while (child > 0) { if (child > parent) { swap(child, parent); child = parent; parent = (child - 1) / 2; } else { break; } } }

【数据结构|【数据结构初阶】大堆与小堆的实现(向上向下调整)TopK问题】数据结构|【数据结构初阶】大堆与小堆的实现(向上向下调整)TopK问题
文章图片

先将双亲结点和孩子结点通过二叉树的特性计算并赋值,通过while(child)来判断左右孩子哪个更小一些得出最小值来和parent进行比较如果child比parents小那么就将其swap(交换)然后再次定义孩子和双亲,直到child大于数组长度(n)退出,这样就形成了一个小堆。
// 堆的构建
创建结点将传进来的数组a的值一个个的进行初始化并调整,从最小的堆也就是在开始的三个数字来进行比较并调整n-1为最后的孩子然后-1除2是最后一个孩子的父亲然后进行调整。
// 堆的构建 void HeapCreate(Heap* hp, HPDataType* a, int n); { HPDataType* php = HPDataType*malloc(sizeof(HPDataType)*n); memset(HPDataType* _a, a, sizeof(HPDataType)); php->capcity = n; php->size = n; for (i = (n - 2) / 2; i > 0; i--) { HeapDown(HPDataType* php; php->size; i); } }

堆的销毁
void HeapDestory(Heap* hp); { free(hp->_a); hp->_a = 0; hp->size = hp->capacity = 0; }

先free掉数据然后将其初始化为0.
堆的插入
先checkcapacity防止溢出。
然后将新加入的数据插入到最后一个数据,通过向上调整法将其调整如果大于parent就交换反之则不动。
void HeapPush(Heap* hp, HPDataType x); { if (hp->capacity >hp-> size) { capacity = capacity * 2; HPDataType* tmp = (HPDataType*)relloc(hp->_a,sizeof( HPDataType)*hp->capacity); hp->_a=tmp =; } hp->a[size++] = x; HeapUp(hp->_a, hp->size,hp->size-1); }

堆顶的删除
先将第一个数据和最后一个数据进行交换位置,size–。此时堆顶就不是最大的了然后再次进行向下调整将次大的调整到堆顶。
void HeapPop(Heap* hp); { swap(hp->_a[0], hp->_a[size - 1]); hp->size--; HeapDown(hp->a,hp->size,0); }

// 取堆顶的数据
a[0]就为堆顶的数据
HPDataType HeapTop(Heap* hp); { return hp->_a[0]; }

// 堆的数据个数
size记录的就是存入数据的个数
int HeapSize(Heap* hp); { return hp->size; }

// 堆的判空
int HeapEmpty(Heap* hp); { return hp->size == 0 ? 1 : 0; }

TOPK问题
TopK问题:找出N个数里面最大/最小的前K个问题。
找最大的前K个,建立K个数的小堆
找最小的前K个,建立K个数的大堆
思路:
如果要在一群数据中找前几个,那么就可通过向上或者向下调整方法进行调整。
首先要把K个数据挑选出来进行堆的创建HeapCreate。(小堆)因为堆中最小的数据在堆顶。
将k+1的值和堆顶数据进行比较如果比堆顶数据大。那么就删除堆顶HeapPop然后堆新数据进行插入,插入后会进行向上调整保证其再自己正确的位置。
void PrintTopK(int* a, int n, int k); { Heap hp; HeapCreate(&hp, a, , k); for (int i = k, i < n; i++) { if (a[i]>HeapTop(&hp)) { HeapPop(&hp); HeapPush(a[i]); } } for (i = 0; i < n; i++) { printf("%d", hp->a[i]); HeapPop(&hp); } }

    推荐阅读