算法: 堆排序
-
堆分析 堆排序适合于求”前K大问题” 海量输出中找出前几大数据 堆排序->二叉树模型 父节点 (3) /
/
(2) (1) 左孩子 右孩子 堆排序两种情况 大根堆:父节点要比左右孩子都大 小根堆:父节点要比左右孩子都小 堆排序需要做两件事: 第一:构建大根堆 (3) /
/
(2) (1) /
/
(4) (5) 上面的树是一个无序堆,构建大根堆步骤如下: 第一步:首先找到堆中的2个父节点(2,3); 第二步:比较2这个父节点的两个孩子(4,5),发现5大 第三步:将较大的右孩子(5)跟父节点(2)进行交换,至此3的左孩子对构建完成, 如下所示 (3) /
/
(5) (1) /
/
(4) (2) 第四步:比较第二个父节点(3)下面的左右孩子(5,1),发现左孩子5大 第五步:然后父节点(3)与左孩子(5)进行交换,注意,交换后,堆可能会遭到破坏, 按照以上步骤一,步骤二,步骤三进行重新构造堆。最后构造的堆如下 (5) /
/
(4) (1) /
/
(3) (2)第二:输出大根堆 至此,我们把大根堆构造出来了,那怎么输出呢?我们做大根堆的目的就是要找出最大值, 那么我们将堆顶(5)与堆尾(2)进行交换,然后将(5)剔除根堆,由于堆顶现在是(2), 所以破坏了根堆,必须重新构造,构造完之后又会出现最大值,再次交换和剔除,最后也就 是要的效果
-
构建堆heapAdjust @param list 数组(待排序集合) @param parent 父节点 @param lenght 输出根堆时剔除最大值使用
function heapAdjust(list, parent, length) {
//temp 保存当前父节点
var temp = list[parent];
//得到左孩子(二叉树定义)
var child = 2 * parent + 1;
while (child < length) {
//如果parent有右孩子,则判断左孩子是否小于右孩子
if (child + 1 < length && list[child] < list[child + 1]) {
child++;
}
//如果父节点大于子节点,就不用交换
if (temp >= list[child]) {
break;
}
//将较大子节点的值赋给父节点
list[parent] = list[child];
//然后将子节点作为父节点,防止是否破坏根堆时重新构造
parent = child;
//找到该父节点较小的左孩子节点
child = 2 * parent + 1;
}
//最后将temp值赋给较大的子节点,以形成两值交换
list[parent] = temp;
}
- 堆排序heapSort
@param list 待排序数组 @param top 前K大
function heapSort(list, top) {
//需要输出的集合
var topNode = [];
//list.length/2-1 为堆中父节点个数
for (var i = list.length / 2 - 1; i >= 0; i--) {
heapAdjust(list, i, list.length);
}
//最后输出堆元素
for (var i = list.length - 1; i >= list.length - top ; i--) {
//堆顶与当前堆得第一个元素进行值对调
var temp = list[0];
list[0] = list[i];
list[i] = temp;
//最大值添加到输出集合
topNode.push(temp);
//因为顺序被打乱,重新构造堆
heapAdjust(list, 0, i);
}
return topNode;
}
- 调用
//获取一个随机数组
function getDatalist() {
var listarr = [];
for (var j = 0; j < 20000; j++) {
listarr[j] = Math.ceil(Math.random() * 20000);
}
return listarr;
}
// 调用
//var list = getDatalist();
//var toplist = heapSort(list, 10);
var list1 = [50, 20, 80, 60, 75, 33, 25, 85, 66, 55];
var toplist1 = heapSort(list1, 3);