堆【算法】
时间:2019-11-07
本文章向大家介绍堆【算法】,主要包括堆【算法】使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
堆分为两种:最⼤堆和最⼩堆,两者之间的差别在于节点的排序⽅式。
- 最⼤堆:⽗节点的值⽐每⼀个字节点的值都⼤。
- 最⼩堆:⽗节点的值⽐每⼀个字节点的值都⼩。
- 堆常常被当作优先队列来⽤,因为可以快速的访问到“最重要”堆元素.
堆和普通树的区别
堆不能取代⼆叉搜索树,它们之间有相似之处也有⼀些不同。
- 节点的顺序:在⼆叉搜索树中,左⼦节点必须⽐⽗节点⼩,右⼦节点必须⽐⽗节点⼤。⽽堆并⾮如此。
- 内存占⽤:普通树占⽤的内存空间⽐它们存储的数据要多。你必须为节点对象以及左/右节点指针分配• 额外多内存。⽽堆仅仅使⽤⼀个数组进⾏存储,且不⽤指针。
- 平衡:⼆叉搜索树必须是“平衡”堆情况下,其⼤部分操作的复杂度才能达到O(log n)。你可以按任意顺序位置插⼊/删除数据,或者使⽤AVL树或者红⿊树,但是堆中实际上不需要整棵树都是有序的。我们只 需要满⾜堆属性即可,所以在堆中平衡不是问题。因为堆中的数据的组织⽅式可以保证O(log n)的性 能。。
- 搜索:在⼆叉树中搜索会很快,但是在堆中搜索会很慢。在堆中搜索不是第⼀优先级因为使⽤堆的⽬的是将最⼤(或者最小)的节点放在最前面,从而快速的进行相关插入、删除操作。
⽤数组存储堆
对于任意⼀个堆,如下图,⾃上⽽下,从左到右把堆中的数据存放到数组⾥。
现在的问题是:⽤数组存储堆,那么就⽤不了指针,那怎么找到某⼀个节点的⽗节点和⼦节点呢?
对任意⼀个节点,i是他的索引,那么:
- 其父节点:\(floor((i-1)/2)\)
- 其左右子节点:\(2*i+1, 2*i + 2\)
如何快速查找到最后一个非叶子节点:
- \((n-1)/2\)
代码
建堆
void make_heap(int* array, int size)
{
for(int i=(size-1)/2; i>=0; --i)
{
// 从索引(size-1)/2 开始,调整堆
adjust_heap(array, i, size);
}
}
void adjust_heap(int* array, int node, int size)
{
int left = 2 * node + 1;
int right = 2 * node + 2;
int max = node;
if(left < size && array[left] > array[max]){
max = left;
}
if(right < size && array[right] > array[max])
{
max = right;
}
if(node != max)
{
swap(array[max], array[node]);
adjust_heap(array, max, size);
}
}
用堆排序数组
已知有一个最大堆,对数组进行非递减排序:
将堆的顶部,与最后一个元素交换。此时除了最后一个元素外,剩下元素所组成的树已经不是堆了。(因为此时顶部的元素可能比较小)。所以,要将剩下的元素通过 adjust函数调整成堆。
for(int i=size-1; i>=0; i--)
{
swap(array[0], array[i]);
adjust_heap(array, 0, i);
}
时间复杂度
- 堆排序时间复杂度:\(O(n log n)\)
- 建堆的时间复杂度:\(O(n log n)\)
- 调整堆的复杂度:\(O(log(n))\)
原文地址:https://www.cnblogs.com/shenhaojing/p/11812455.html
- CSS魔法堂:小结一下Box Model与Positioning Scheme
- jboss EAP 6.2+ 通过代码控制JNDI数据源
- jboss CLI 命令行接口学习(适用JBOSS EAP 6.2+)
- WebComponent魔法堂:深究Custom Element 之 面向痛点编程
- 修复bootstrap daterangepicker中的3个问题
- 搭建AngualarJS开发环境
- CSS魔法堂:重拾Border之——更广阔的遐想
- Jboss EAP:native management API学习
- linux:手动校准系统时间和硬件CMOS时间
- CSS3魔法堂:说说Multi-column Layout
- 数据可视化-EChart2.0使用总结2
- rpc框架之 thrift 学习 2 - 基本概念
- rpc框架之avro 学习 1 - hello world
- 探讨Android中的内置浏览器和Chrome
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法