🎆前言🎆✨笔者也仅是大一萌新,写博客为了记录和巩固知识✨
🥰赠人玫瑰,手留余香,欢迎各位读者进行交流和建议🥰
🌹能与大家一起学习,一起进步是我的荣幸🌹
🤞如果这篇文章有帮助到您,还请留个赞支持一下哦🤞
🎃前情提要🎃
🔎目录:
🔎 二叉树的顺序结构:
普通的二叉树不适合用数组来存储,因为可能会存在大量的空间浪费,所以适合使用顺序结构存储的通常为完全二叉树。而堆就是使用顺序结构来存储的(这里的堆和我们学内存的堆是不同的,一个是数据结构,一个是操作系统中管理内存的一块区域分段)。
🔎 堆的概念和结构:
一个完全二叉树以顺序存储的方法存入一个一维数组中,那么这个堆可以分为:
大堆/大根堆:树中的父亲都大于等于孩子
小堆/小根堆:树中的父亲都小于等于孩子
堆主要用来解决:堆排序,TopK
堆的性质:
- 堆中某个结点的值总是不大于或不小于父亲的值
- 堆总是一棵完全二叉树
🔎 实现堆的方法
⭐ 建堆的时间复杂度:
⭐ 函数声明:
#pragma once #include <stdio.h> #include <assert.h> #include <stdlib.h> #include <time.h> #include <stdbool.h> typedef int HPDataType; typedef struct Heap { HPDataType* a; size_t size; size_t capacity; }HP; void Swap(HPDataType* pa, HPDataType* pb); //交换函数 void HeapPrint(HP* php); //打印函数 void HeapInit(HP* php); //初始化 void HeapDestroy(HP* php); //清空 void HeapPush(HP* php, HPDataType x); //插入 void HeapPop(HP* php); //删除 bool HeapEmpty(HP* php); //判空 size_t HeapSize(HP* php); //树的大小 HPDataType HeapTop(HP* php); //根结点 void AdjustUp(HPDataType* a, size_t child); //向上调整 void AdjustDown(HPDataType* a, size_t size, size_t root); //向下调整
⭐ 交换函数:
注意:形参接收实参的值,如果不用return的话出了该函数就会被销毁,必须要接收地址才能改变实参的值
void Swap(HPDataType* pa, HPDataType* pb) //交换 { HPDataType tmp = *pa; *pa = *pb; *pb = tmp; }
⭐ 打印函数:
直接进行遍历打印即可
void HeapPrint(HP* php) { assert(php); for (size_t i = 0; i < php->size; i++) { printf("%d ", php->a[i]); } printf("\n"); }
⭐ 初始化:
防止杂乱数据出现我们都先置空
void HeapInit(HP* php) { assert(php); php->a = NULL; php->size = php->capacity = 0; }
⭐ 清空函数:
在释放空间后也要把指针置空防止出现野指针
void HeapDestroy(HP* php) { assert(php); free(php->a); php->a = NULL; php->size = php->capacity = 0; }
⭐ 插入函数:
要注意的是,我们不能像之前的线性表那样,只把数据放进去,在树中我们还需要进行调整,不然会破坏树的结构(比如:我在一个父节点为100的小堆中插入一个99,那么结构显然是不对的),这时我们需要用到向上调整法
void HeapPush(HP* php, HPDataType x) //时间复杂度O(logN) { assert(php); if (php->size == php->capacity) //朴实无华的扩容操作 { size_t newcapacity = php->capacity == 0 ? 4 : php->capacity * 2; HPDataType* tmp = realloc(php->a, sizeof(HPDataType) * newcapacity); if (tmp == NULL) { printf("realloc fail!"); exit(-1); } php->a = tmp; php->capacity = newcapacity; } php->a[php->size] = x; //将x放入树中 php->size++; AdjustUp(php->a, php->size - 1); //此时x在下标为size-1的位置 }
⭐ 向上调整法:
思路:
为了不让树的结构被破坏,我们需要调整一下不符合规则的插入数据,而插入的这个数据影响的是它这条路径的所有祖先,如下图的100影响的是11-10-4,所以我们只需要将100与这条路径的数据进行对比,满足规则就停下来,不满足规则就继续对比
图示(大堆演示):