JS实现堆排序

一,堆的概念
堆是一棵顺序存储的二叉树
其中每个节点的关键字都不大于其子节点的关键字,这样的堆称为小根堆
其中每个节点的关键字都不小于其自己点的关键字,这样的堆称为大根堆
下面是一个典型的小根堆:

二,堆的调整
堆的调整是为了保持堆的特性而做的一个操作,对以某一个节点为根的子树做堆调整,其实就是将该根节点进行”下沉操作”(具体是通过和子节点的交换完成的),一直下沉到合适位置,使得刚才的子树满足堆的性质为止。
对大根堆的调整步骤如下:
1,在对应元素A[i],找到左孩子A[left(i)]和右孩子A[right(i)]中最大的那一个,将其下标存储在largest中。
2,如果A[i]已经是最大元素,则程序结束
3,否则,i的某个子节点为最大的元素,将A[largest]与A[i]交换
4,再从交换的子节点开始,重复1,2,3步骤,直至叶子节点,算完成一次堆调整。
做一次堆调整的时间复杂度为lgn,从二叉树的根节点到叶子结点,树的深度为lgn,也就是需要下沉的最大次数为lgn。
三,堆的建立
建堆是一个通过不断的堆调整,使得整个二叉树满足堆性质的操作。在数组中,我们一般从下标n/2的数开始作调整,一直到下标为0的数
疑问:为什么是从n/2的数开始?因为下标大于n/2的数都是叶子节点,其子树已经满足堆的性质,所以不用再调整了。下图为一个小根堆的建立图示:


四,堆的排序
堆的排序是堆建立完成之后进行的,假设数组存储成大根堆的形式之后
第一次将A[0]与A[n-1]交换,然后将A[0~n-2]数组进行堆恢复操作(做堆调整)。
第二次将A[0]与A[n-2]交换,然后将A[0~n-3]数组进行堆恢复操作(做堆调整)。
重复这样的操作,直到A[0]与A[1]交换,排序结束。
由于每次都是将最大的数并入到后面的有序区间,所以整个数组是有序的,上述步骤产生的是升序排列。一个大根堆排序过程的示意图:




五,堆排序性能分析
堆排序时间=建堆时间+堆恢复时间
建堆时间:建堆的过程就是堆不断调整的过程,前面分析过一次堆调整的时间复杂度为O(lgn),堆建立过程调整了n/2次,因此时间复杂度是O(nlgn).
堆恢复时间:堆恢复操作共进行了n-1次堆调整操作,因此,时间复杂度是O(nlgn)
综上得:堆排序的最差、最优、平均时间复杂度均是O(nlgn) 不稳定

“空间复杂度”指占内存大小,堆排序每次只对一个元素操作,是就地排序,所以空间复杂度是O(1)

六,代码实现

1,大根堆,升序排列

 /**
     * 
      *@Description:堆排序
      *@param arr
      *@author  肖芳   
     */
function headSort(arr){
	buildHeap(arr);//构建堆
	var len = arr.length;
	for(var i=len-1;i>0;i--){
		swap(arr,0,i);//交换堆的第一个元素和最后一个元素
		heapify(arr,i);//调整堆
	}
	return arr;
}
 /**
     * 
      *@Description:创建堆
      *@param arr
      *@author  肖芳  
     */
function buildHeap(arr){
	var len = arr.length;
	if(len == 0)
		return;
	for(var i=Math.floor(len/2);i>0;i--){
		heapify(arr,i);
	}
}
/**
     * 
      *@Description:调整堆
      *@param arr 调整数组
      *@param i 跟
      *@author  肖芳  
     */
function heapify(arr,i){
	var left = 2*i+1;
	var right = 2*i+2;
	var largest = i;
	var len = arr.length;
	if(left <len && arr[left]>arr[largest]){//先判断左节点还否超出
		largest=left;
	}
	if(right <len && arr[right]>largest){//有节点是否超出 找出最大的子节点
		largest=right;
	}
	if(largest != i){
		swap(arr,i,largest);//交换 largrst为i
		heapify(arr,largest);//递归调整
	}
}
/**
     * 
      *@Description:交换
      *@param arr
      *@author  肖芳  
     */
function swap(arr,i,j){
	var temp=arr[i];
	arr[i] = arr[j];
	arr[j] = temp;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值