虽然前端面试中不多会考到算法类的题目,可是你去好比像腾讯同样的大厂面试的时候就知道了,对基本算法的掌握对于从事计算机科学技术的咱们来讲,仍是必不可少的,天天花上 10 分钟,轻松了解基本算法概念以及前端的实现方式。前端
另外,掌握了一些基本的算法实现,对于咱们平常开发来讲,也是如虎添翼,能让咱们的 js 业务逻辑更趋高效和流畅。面试
今天这个算法稍微比较复杂,牵扯到的概念也比较多,须要先了解基础知识。我给每篇文章的定位是 10 分钟内应该要掌握下来,因此我就擅做主张地将堆排序算法讲解分割为上、下两篇文章了,但愿能让你们阅读起来更清爽愉快。算法
《堆排序(上)》文章结构:数组
《堆排序(下)》文章结构:微信
要了解堆,必须先了解一下二叉树,二者关系在下一步阐述。数据结构
二叉树(Binary Tree)是每个节点最多有两个分支的树结构,一般分支被称做「左子树」和「右子树」,分支具备左右次序,不能随意颠倒。ui
二叉树第 i
层最多拥有 2^(i-1)
个节点,深度为 k
的二叉树最多共有 2^(k+1)-1
个节点,且定义根节点所在的层级 i=0
,所在的深度 k=0
。注意该定义在全文起做用,后续不继续说起。spa
二叉树示意图code
假设某个二叉树深度为 k
,第 i
层拥有 2^(i-1)
个节点,且总共拥有 2^(k+1)-1
个节点,这样的二叉树称为「满二叉树」。cdn
换句话说,二叉树的每一层都是满的,除了最后一层上的节点,每个节点都具备左节点和右节点。
满二叉树示意图
假设某个二叉树深度为 k
,共有 n
个节点,当且仅当其中的每个节点,均可以和一样深度为 k
的满二叉树上的,按层序编号相同的节点,也就是序号为 1
到 n
的节点,均一一对应时,这样的二叉树称为「彻底二叉树」。
满二叉树必定是彻底二叉树,可是彻底二叉树不必定是满二叉树。
彻底二叉树示意图
以下的就不是彻底二叉树,树 1 中 10 号节点缺失,树 2 中 六、7 号节点缺失,树 3 中 十、11 号节点缺失。
不是彻底二叉树示意图
堆(Heap),一类特殊的数据结构的统称,一般是一个能够被看作一棵树的数组对象。
堆的实现经过构造二叉堆(binary heap),实为二叉树的一种,因为其应用的广泛性,当不加限定时,均指该数据结构的这种实现。
堆,是彻底二叉树。
堆和数组相互关系示意图
对于给定的某个节点的下标 idx
,能够很容易地计算出这个节点的父节点与孩子节点的下标:
// 计算父节点的下标
var getParentPos = function(idx){
return Math.floor(idx / 2);
}
// 计算左子节点的下标
var getLeftChildPos = function(idx){
return 2*idx;
};
// 计算右子节点的下标
var getRightChildPos = function(idx){
return 2*idx + 1;
};
复制代码
以下图,取下标 idx = 4
的节点,则其父节点的下标就为 Math.floor(4/2) === 2
,其左子节点的下标就为 2*4 === 8
,其右子节点的下标就为 2*4 + 1 === 9
。
计算亲属节点位置示意图
但将堆转换为数组时,因为数组的初始化下标始终为 0
,因此咱们的堆数据结构模型在此时要发生以下改变:
改变数据结构模型示意图
一样的,以上的算法也须要作一下微调:
// 计算父节点的下标
var getParentPos = function(idx){
return Math.floor((idx-1) / 2);
}
// 计算左子节点的下标
var getLeftChildPos = function(idx){
return 2*idx + 1;
};
// 计算右子节点的下标
var getRightChildPos = function(idx){
return 2 * (idx+1);
};
复制代码
二叉堆通常分为两种:「大顶堆」和「小顶堆」。
假设有一个堆,其中每一个节点的值都大于或等于其左右孩子节点的值,则该堆称为「大顶堆」。「大顶堆」的最大元素值出如今根节点。
大顶堆示意图
假设有一个堆,其中每一个节点的值都小于或等于其左右孩子节点的值,则该堆称为「小顶堆」。「小顶堆」的最小元素值出如今根节点。
小顶堆示意图
以为本文不错的话,分享一下给小伙伴吧~