数据结构之堆排序

强烈推荐这个up主的视频:https://www.bilibili.com/video/av47196993,声音好听,讲的又清楚。

什么是堆

首先,堆满足以下两个条件:

  1. 一定是一个完全二叉树的结构。
  2. 如果父节点 > 两个子节点 :称之为大根堆
    如果父节点 < 两个子节点 :称之为小跟堆

以大根堆为例:
在这里插入图片描述
可以知道,对于任意一个节点 i ,我们都可以找到其父节点和子节点的位置:

父节点: (i-1)/2    向上取整
左节点: i*2+1
右节点: i*2+2

首先考虑最小的堆,只有三个节点。
那么想把它变成一个堆,就比较根节点和左右节点,取出最大的值max作为根。
然后接着对max所在位置节点,继续比较它和它的左右节点。。。重复操作,直到叶子节点。
在这里插入图片描述
heapify函数能做到从根节点开始,一直到最下面的节点这一条路径满足堆的条件。

function heapify(tree,n,i){
	if(i > n) return;
	var c1 = i*2+1;
	var c2 = i*2+2;
	var max = i;
	//确定max指针指向(根,左右节点中)最大的数
	if( c1 < n && tree[max]<tree[c1]){
		max = c1;
	}
	if ( c2 < n && tree[max]<tree[c2]) {
		max = c2
	}
	//如果max指向的不是根,就把max指向的节点提到根上来
	if(max !== i){
		[tree[max],tree[i]] =  [tree[i],tree[max]];
		//对叶子节点继续进行建堆操作
		heapify(tree,n,max);
	}
	// console.log(tree);
}
构建一个堆

构建一个堆,其实就是不停的进行heapify过程。对于一个乱序的树,我们从最后一个非叶子节点开始进行heapify。要找到最后一个非叶子节点,其实就是,最后一个最后一个叶子节点的父节点:

var parent = parseInt((lastNode-1)/2);
//从下至上构建堆,n是tree的长度
function buildHeap(tree,n){
	var lastNode = n-1;
	var parent = parseInt((lastNode-1)/2);
	/*
	这里一定是从最后一个非叶子节点开始,往上走,这样就保证该节点的子节点已经形成堆了,
	只需考虑该节点和其父节点。如果从根节点开始向下走,比如这个例子中
	会出现[5, 10, 3, 1, 2, 4 ],因为根节点已经heapify过了,不会再执行,导致10和5不会再交换
	*/
	for(var x = parent ; x >= 0 ; x--){
		heapify(tree,n,x);
	}
}
堆排序(Heap Sort)

堆排序:首先构建好一个堆,之后把root的值与最后一个叶子节点对调,切掉最后一个节点。之后重新heapify,重复上述操作。
在这里插入图片描述

//堆排序
function heapSort(tree,n){
	//初建一个堆
	buildHeap(tree,6);
	//循环,i作为数组最后节点的位置,每次减1,相当于切掉最大的值。
	for (var i = n - 1; i >= 0; i--) {
		//交换根节点与最后一个节点
		[tree[i],tree[0]] = [tree[0],tree[i]];
		//对剩余节点进行heapify,把剩余数中最大值提到tree[0]中
		heapify(tree, i, 0);	
	}
	
}
heapSort(tree,6);
console.log(tree);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值