当前位置: 首页 > news >正文

数据结构初阶 —— 树(堆)

目录

一,堆

堆的概念

向下调整法(数组)

向上调整法(数组)

堆的创建(建堆)

堆的实现 


一,堆

堆的概念

  • 如有个关键码的集合K={k_{0}k_{1}k_{2},...,k_{n-1}},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足 k_{i}<=k_{2*i+1} 且 k_{i}<=k_{2*i+2} (k_{i}>=k_{2*i+1} 且 k_{i}>=k_{2*i+2}),i=0、1、...,则称为小堆(大堆);

小堆

  • k_{i}<=k_{2*i+1} 且 k_{i}<=k_{2*i+2} ,即所有节点小于等于孩子;
  • 根节点最小,叫做最小堆或小根堆;

大堆

  • k_{i}>=k_{2*i+1} 且 k_{i}>=k_{2*i+2} ,即所有节点大于等于孩子;
  • 根节点最大,叫做最大堆或大根堆;

堆的性质

  • 堆中某个节点的值,总是不大于或不小于其父节点的值;
  • 根一定是最值(最大值或最小值);
  • 堆总是一颗完全二叉树,适合顺序结构存储;

向下调整法(数组)

  • 将数组看做为一颗完全二叉树,可使用向下调整法创建堆;
  • 前提条件为,此二叉树的左右子树需是一个堆,只有根节点不满足堆要求;
  • 从根开始,与左右子节点中的最小值,比较并交换,依次类推,直到比父亲大或到叶子节点终止;
  • 时间复杂度,O(logN);
  • 注,向上调整法类似;
int array[] = {27,15,19,18,28,34,65,49,25,37};

//向下调整法,小堆
void Swap(int* px, int* py)
{int tmp = *px;*px = *py;*py = tmp;
}void AdjustDown(int* arr, int n, int parent)
{int child = 2 * parent + 1;//无孩子节点或父亲小于孩子,即终止while (child < n){if (child + 1 < n && arr[child + 1] < arr[child])child++;if (arr[parent] > arr[child]){Swap(arr + parent, arr + child);parent = child;child = 2 * parent + 1;}elsebreak;}
}

向上调整法(数组)

//向上调整法
void AdjustUp(int* arr, int child)
{int parent = (child - 1) / 2;//大堆//根节点或父亲大于孩子,即终止while (child > 0){if (arr[parent] < arr[child]){Swap(arr + parent, arr + child);child = parent;parent = (child - 1) / 2;}elsebreak;}
}

堆的创建(建堆)

  •  即对数据如数组(可看为完全二叉树),将其构建为堆;
  • 方法为,从倒数第一个非叶子节点的子树开始调整,直到根节点为止;
  • 即每次调整时,使用向下调整法;
  • 建堆时间复杂度,O(N),下面有证明;
  • 注,也可使用向上调整法建堆,但初始化堆的个别元素位置可能不一样;
int arr[] = {1,5,3,8,7,6}; 
//建堆-向下调整法
void Heap(int* arr, int n)
{int i = (n - 1 - 1) / 2; //最后节点的父节点for (i; i >= 0; i--){AdjustDown(arr, n, i);}
}
//建堆-向上调整法
void Heap(int* arr, int n)
{int i = 1; for (i; i < n; i++){AdjustUp(arr, i);}
}

建堆时间复杂度

堆排序  

  • 升序,建大堆(将最大的数换到最后,在将剩下的数向下调整下,选出次大数,依次类推);
  • 降序,建小堆(将最小的数换到最后,在将剩下的数向下调整下,选出次小数,依次类推);
  • 整体的时间复杂度,O(N*logN);
  • 如升序建小堆(或降序建大堆)的话,选出最值后,需在继续建堆(O(N)),效率较低,还不如直接遍历,建堆的价值未体现;
//建堆排序
void HeapSort(int* arr, int n)
{//建堆 - O(N)int i = (n - 1 - 1) / 2; //最后节点的父节点for (i; i >= 0; i--){AdjustDown(arr, n, i);}//排序 - O(N*log(N))int end = n - 1;while (end){Swap(arr, arr + end);AdjustDown(arr, end, 0);end--;}
}

堆的实现 

//堆
typedef int HPDataType;typedef struct Heap
{HPDataType* data;int size;int capacity;
}Heap;//初始化
void HeapInit(Heap* php, HPDataType* arr, int n);//释放销毁
void HeapDestroy(Heap* php);//插入数据并保持堆
void HeapPush(Heap* php, HPDataType* x);//删除堆顶数据并保持堆
void HeapPop(Heap* php);//返回堆顶数据
HPDataType HeapTOP(Heap* php);//返回堆节点个数
int HeapSize(Heap* php);//判断释放为空
bool HeapEmpty(Heap* php);

注:完整接口实现代码路径https://gitee.com/napoleoncode/start-code/tree/master/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84/06_Heap

TOP-K问题

  • 直接排序,O(N*log(N));
  • 建个N个数的堆,并取出前K个数,O(N+K*log(N));
  • 建个K个数的小堆,然后将剩下的数依次与堆顶比较,大即入堆,最后此堆即为最大的K个数,O(N*log(K));(如N非常大内存不够,前两种方法即适用了);
  • 注,通常K远小于N;
//TOP-K
void TOPK(int* arr, int n, int k)
{Heap hp;//建堆HeapInit(&hp, arr, k);int i = k;for (i; i < n; i++){//替换if (HeapTop(&hp) > arr[i]){HeapPop(&hp);HeapPush(&hp, arr[i]);}}HeapPrint(&hp);HeapDestroy(&hp);
}

http://www.lryc.cn/news/63795.html

相关文章:

  • 一文看懂低代码,5分钟从入门到原理全搞定
  • MetaERP系统主要干什么的,华为自研ERP的路子是否可以效仿?
  • 自动驾驶——离散LQR的黎卡提方程Riccati公式推导与LQR工程化
  • 28.Mybatis的入门
  • Android Jetpack 从使用到源码深耕【ViewModel从实践到原理 】(三)
  • 什么性格的人适合报考环境科学类专业?高考选专业
  • Python中的异常处理机制可以帮助程序员在程序运行过程中遇到错误时进行处理
  • TCP之报文格式解析
  • qemu-基础篇(二)——裸机 arm 程序环境搭建
  • JSP+SQL基于JSP的学生信息管理系统(源代码+论文+答辩PPT)
  • docker上部署程序后无法连接数据库的问题
  • Ucore lab4
  • AI失业潮来袭,某些部门裁员过半
  • git 撤销add/commit,以及更换源命令
  • 3dMax需要什么样的硬件环境才能更好的工作?
  • python-使用Qchart总结4-绘制多层柱状图
  • Java学习笔记-02
  • 中通快递财报预测:中通快递2023年收入和利润将大幅下降
  • Javaweb | 状态管理:Session、Cookie
  • Redux
  • Nacos配置中心的详解与搭建
  • Java入门教程||Java 封装||Java 接口
  • 微软开源AI修图工具让老照片重现生机
  • 什么是 Docker?它能用来做什么?
  • 生成器的创建方式(py编程)
  • 百胜中国:未来将实现强劲增长
  • 【Celery】任务Failure或一直超时Pending
  • 【严重】VMware Aria Operations for Logs v8.10.2 存在反序列化漏洞(CVE-2023-20864)
  • java实现乘法的方法
  • SSD目标检测