:是用数组实现的完全二叉树,没有使用指针,根据数组的下标进行构建堆
eg:parentIndex = i;—》 leftIndex = 2i+1;rightIndex = 2i+2;
堆的分类:大根堆,小根堆。大根堆的每个子树,根节点是整个树中最大的数据,每个节点的数据都比其子节点大
小根堆的根节点数据是最小的数据,每个节点的数据都比其子节点小

注意:堆的根节点中存放的是最大或者最小元素,但是其他节点的排序顺序是未知的。例如,在一个最大堆中,最大的那一个元素总是位于 index 0 的位置,但是最小的元素则未必是最后一个元素。–唯一能够保证的是最小的元素是一个叶节点,但是不确定是哪一个。
(以小根堆为例 讲解 堆的构建,插入和删除过程)
一,堆的构建
从末尾节点的父节点的这棵树开始调整,根据小根堆的性质,越小的数据往上移动,注意,被调整的节点还有子节点的情况,需要递归进行调整。



2和3交换之后,3所处的节点还有子节点,需要递归检验3所在树是否也符合小根堆的性质

注意:此时9和1发生交换之后,9所处的节点具有子节点,递归调整9所处的树

至此,小根堆构建的过程就完成了,下面看下代码层面的实现

private List<Integer> arr;
/*** 构建最小堆,从最后一个节点的父节点开始调整(也可以对数组中某段连续数据即下标从firstIndex -> endIndex进行建堆)* @param firstIndex 起始下标* @param enIndex    结束下标*/
public void buildMinHeap(int firstIndex,int enIndex) {for (int i = enIndex/2; i >= firstIndex; i--) {adjustDown(i,enIndex);}}/*** 调整当前子树,越小的数据往上移动,注意调整的该节点还有子节点的情况,所以需要递归调整。* @param parentIndex  父节点的下标*/private void adjustDown(int parentIndex,int endIndex) {int left = 2 * parentIndex + 1;int right = 2 * parentIndex + 2;//最小值的下标int minIndex = parentIndex;if (left < endIndex && arr.get(left) < arr.get(minIndex)) {minIndex = left;}if (right < endIndex && arr.get(right) < arr.get(minIndex)) {minIndex = right;}if(minIndex == parentIndex){return;}//交换元素swap(parentIndex,minIndex);//递归调整adjustDown(minIndex,endIndex);}private void swap(int parentIndex,int minIndex){int temp = arr.get(parentIndex);arr.set(parentIndex,arr.get(minIndex));arr.set(minIndex,temp);}

二、插入
新增元素首先插入在堆的末尾元素,然后依据小根堆的性质,自底向上,递归调整。
以上面构建的小根堆为例,新插入元素0。
1,首先在堆的末尾插入新增元素

2,自底向上,递归调整其父节点



(插入是在小根堆构建完成的基础上进行的操作,所以在交换之后其子节点所在的树也都是小根堆,所以不需要再进行递归调整)
代码实现:

/*** @param item 要插入的元素*/public void insertToMinHeap(int item){arr.add(item);//根节点if(arr.size() == 1){return;}adjustUp(arr.size()-1);}/*** 向上调整* @param childIndex 要往上调整的子节点的下标*/private void adjustUp(int childIndex){int parentIndex = (childIndex - 1)/2;int parentItem = arr.get(parentIndex);int childItem = arr.get(childIndex);if(parentItem > childItem){swap(parentIndex,childIndex);adjustUp(parentIndex);}}

三、堆删除
对于最大堆和最小堆,删除操作是针对堆顶元素而言的,即把末尾元素移动到堆顶,再自定向下(重复构建堆的操作),递归调整。
1,将末尾元素移动到堆顶




此时所有的子树都符合小根堆的性质了,即完成堆调整。
代码实现:

 public int deleteMinHeap(){//取出最小元素,并将最后一个元素置顶int minItem = arr.get(0);arr.set(0,arr.get(arr.size()-1));//移除末尾元素if(arr.size() > 1){arr.remove(arr.size() - 1);}//向下调整堆(该实现见上面)adjustDown(0,arr.size()-1);return minItem;}

四、堆排序:(升序–》大根堆,降序–》小根堆)
利用大根堆/小根堆的特性(以小根堆为例),第一次建完小根堆之后,最小的元素将位于0号下标,将0号元素和最后一个元素交换,然后再将剩下的树再建小根堆,循环进行此操作直到完成所有数据
1,将无序数组构建成小根堆

2,将堆顶元素和末尾元素交换位置,使最小元素落在末尾

3,除了2步骤落到末尾的元素,对剩下的元素继续建小根堆(重复1,2的动作),直到完成所有的元素即完成排序

代码实现:

/*** 先建成最小堆,再将堆顶元素和堆尾元素交换,除了当前堆的堆尾元素,对剩下的元素再次进行建堆*/public void heapSort(){for(int i = 0;i<arr.size();i++){buildMinHeap(0,arr.size()-1-i);swap(0,arr.size()-1-i);}}

五,堆和二叉排序树的区别
内存占用:二叉排序树占用的内存空间比我们存储的数据要多,需要分配额外的内存来存储指针指向其左右子节点。堆的实现结构是数据,根据数组具有下标这一特性来执行左/右子节点。
节点的顺序:在二叉排序树中,左子节点必须比父节点小,右子节点必须比父节点大。但是在堆中并非如痴,在小根堆中两个子节点都必须比父节点小,并且左右子节点的数据大小是不确定的。
搜索性能:二叉排序树是为了实现动态查找而涉及的数据结构,它是面向查找操作的,在二叉排序树中查找一个节点的平均时间复杂度是O(logn);在堆中搜索并不是第一优先级,堆是为了实现排序而实现的一种数据结构,它不是面向查找操作的,因为在堆中查找一个节点需要进行遍历,其平均时间复杂度是O(n)。

小根堆创建,插入,删除,排序等操作图解相关推荐

  1. 再写堆(堆的性质,向下调整,建堆,堆的插入删除初始化,堆排序,TopK问题)

    堆的概念 如果有一个关键码的集合K={k0,k1,k2,-,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储再一个一维数组中,并满足:Ki<=K2i+1且Ki<=K2i+1(Ki ...

  2. 二叉搜索树-php实现 插入删除查找等操作

    二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值: 若它的 ...

  3. c语言用链表对学生成绩排序,学生成绩排序和平均分计算利用c语言链表的创建插入删除.doc...

    #define NULL 0 #define LEN sizeof(struct student) struct student { long num; float score; struct stu ...

  4. MySQL 索引的创建、删除和查看操作

    ybm(使用部门)一般只有几条记录,除了主关键字外对任何一个字段建索引都不会产生性能优化,实际上如果对这个表进行了统计分析后ORACLE也不会用你建的索引,而是自动执行全表访问 1.索引作用 在索引列 ...

  5. oracle创建、删除索引等操作

    1.创建索引 create index 索引名 on 表名(列名); 2.删除索引 drop index 索引名; 3.创建组合索引 create index 索引名 on 表名(列名1,,列名2); ...

  6. 二叉搜索树(创建,插入,删除):基础篇,适合新手观看。

    1.1 二叉搜索树的插入 二叉搜索树的概念相信大家都很清楚,无非就是左小右大 创建二叉搜索树,其实就是多次调用二叉搜索树的插入方法,所以首先我们来讲讲如何插入节点到二叉搜索树里,假设一颗二叉搜索树如下 ...

  7. 链表(创建,插入,删除和打印输出

    http://www.bianceng.cn/Programming/C/200705/327.htm  (以下不全,去此网址看) 数组作为存放同类数据的集合,给我们在程序设计时带来很多的方便,增加了 ...

  8. C/C++创建和删除文件夹操作(包含多级)

    下面给出创建单个文件夹的方法,每一种方法后面都紧跟着对应的删除文件夹的方法. 此处参考博主. 一:调用Windows API函数 CreateDirectory()和 RemoveDirectory( ...

  9. 由一维数组创建小根堆

    1.结构体和头文件: #include<iostream> #include<vector>using namespace std;struct MinHeap //也可以不用 ...

最新文章

  1. UVA1601万圣节的早上
  2. AspectJ对AOP的实现
  3. 用Lighttpd做图片服务器
  4. YII2 整合百度UEditor上传图片到阿里云OSS
  5. python提取数据包中的文件_Python-对Pcap文件进行处理,获取指定TCP流
  6. 陕西省高级职称 计算机要求,陕西省卫生高级职称评审申报条件
  7. mysql5.7免安版配置_mysql5.7免安装版配置
  8. 计算机网络实验1线缆制作,计算机网络技术实验报告1双绞线的制作
  9. Nacos系列:欢迎来到Nacos的世界!
  10. NativeXml (2):对象建立
  11. 牛客网算法工程师能力评估
  12. C++ STL string字符串替换 replace函数的使用
  13. 循环双链表的手动构建总结
  14. 【pytorch】(断点)继续上次训练
  15. scala字符串变量替换
  16. python启动方法_python启动服务
  17. 微分几何的20-23节笔记
  18. 002输出一个正方形
  19. CHM格式打开以后无法显示解决
  20. 0203逻辑卷管理、RAID磁盘阵列、VD0、管理运行级别

热门文章

  1. 怎么将两个pdf文件合并在一起
  2. 2020 DASCTFBJD 部分题解
  3. 身份证号的验证与解析
  4. 数据中台已成下一风口,它会颠覆数据工程师的工作吗?
  5. 计算机病毒的入侵路径,计算机病毒的入侵方式有哪些?
  6. Java File文件流读取文件夹内的文件并替换文件内容
  7. win10系统显示打印机未连接到服务器,解决win10提示“Windows无法连接到打印机”的方法...
  8. latex并排显示多个图片
  9. 基于matlab的蝗虫优化(Grasshopper Optimization Algorithm,GOA)算法仿真
  10. thinkpad E430 电源连接未充电的问题解决方法