算法——堆排序(Heapsort)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012194956/article/details/79407588

首先需要说明一下“堆”这个数据结构:

完全二叉树(Complete Binary Tree):若设二叉树的深度为h,除第h层外,其他各层(1~h-1)的结点都达到最大个数,第h层所有的结点都连续集中在最左边,这就是完全二叉树。

是具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,称为大顶堆;每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆

堆的示意图:


上图中,我们对堆中的结点按层进行编号,将这种逻辑结构映射到数组中就是下面这个样子:


该数组从逻辑上讲就是一个堆结构,我们可以用简单的公式来描述一下对的定义:

大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]  

小顶堆:arr[i] <= arr[2i+1] && arr[i] <= arr[2i+2]  

扫描二维码关注公众号,回复: 3191017 查看本文章


堆排序

堆排序是利用堆这种数据结构而设计的一种排序算法,它是一种选择排序

堆排序的思想:

(1)构造初始堆。将给定无序序列构造成一个大顶堆(一半升序采用大顶堆,降序采用小顶堆)。假设将给定序列按照上图进行按层绘制成一个完全二叉树,则从最后一个非叶子(对应序列为arr.length/2-1)节点开始,从左至右,从上至下。

(2)将堆顶元素与末尾元素进行交换,使末尾元素最大。然后继续调整剩下的数组元素,使其成为一个大顶堆,得到第二大元素。

(3)重复上述步骤,直到形成一个有序序列

堆排序的时间复杂度:最好、最坏、平均都为O(nlogn)

实现代码:

//处理一个无序数组,将其构造成一个大顶堆
function buildHeap(arr){
	var count=Math.floor(arr.length/2); //非叶子结点的个数(对应最后一个非叶子节点的序列号为count-1)
	//调整顺序,调整次数为count,第i次调整,对应确定最终大顶堆的非叶子节点i的值
	for(var i=count-1;i>=0;i--){
		adjustHeap(arr,i,arr.length); //调整以使序列号为i的非叶子节点及其所有子节点构成一个大顶堆
	}
}

function adjustHeap(arr,parentInd,length){
	//假设数组第一个索引值为0(默认),则父节点下标为i时,其左孩子为2*i+1,右孩子为2*i+2
	var tmp=arr[parentInd];
	var leftInd=parentInd*2+1; //父节点必定有一个左孩子,需要判断是否有右孩子
	var ind=leftInd;
	while(ind<length){
		if((ind+1)<length && arr[ind]<arr[ind+1]){//如果右孩子存在且大于左孩子,则将索引定位到右孩子
			ind++;
		} 
		//ind表示的是子节点中数值较大的那一个孩子对应的索引值
		if(arr[parentInd]<arr[ind]){ //如果父节点小于左右孩子的最大值,则交换
			arr[parentInd]=arr[ind];
			arr[ind]=tmp;
			parentInd=ind; //将父节点定位到子节点中较大的那一个(针对子节点同时也是非叶子节点的情况)
			ind=parentInd*2+1; //将ind定位到父节点的左孩子(此时需要同上判断ind<arr.length是否成立,也是判断重定位的parentInd是否为非叶子节点)
		}else{
			break;
		}
	}
}

function heapSort(arr){
	//构建大顶堆
	buildHeap(arr);
	//堆顶元素交换
	var tmpe;
	for(var i=arr.length-1;i>0;i--){
		tmpe=arr[0];
		arr[0]=arr[i];
		arr[i]=tmpe; 
		adjustHeap(arr,0,i); //调整剩余数组,使其中最大的数调整到堆顶
	}
	return arr; //对排序后生成的有序数组
}

结果测试:


本文参考:

图解堆排序

JS实现堆排序


猜你喜欢

转载自blog.csdn.net/u012194956/article/details/79407588
今日推荐