堆的构建以及利用堆排序

堆其实就是一个基于数组的二叉树,由于本身是数组,因此相比于普通二叉树,它可以通过简单的数值计算就能够访问节点。堆有最大堆和最小堆之分,最大堆中每个父节点值大于或等于子节点的值,最小堆则相反。

对于n元素数值而言,它的每个节点arr[i]的子节点点索引分别问2*i+1,2×i+2,根节点为0

以最大堆为例,向一个堆中添加节点时,需要将父节点路径上的节点向下移动一层,知道这个节点位于正确的位置

public static<T> void pushHeap(T[]arr,int last,T item,Comparator<? super T> comp)
	{
		int currentPos=last;
		int parentPos=(currentPos-1)/2;
		while(currentPos!=0)
		{
			if(comp.compare(item, arr[parentPos])<0)//易错点
			{
				arr[currentPos]=arr[parentPos];
				currentPos=parentPos;
				parentPos=(currentPos-1)/2;
			}
			else
				break;
		}
		arr[currentPos]=item;
	}

堆的删除节点的操作一般情况下被限制只能对根节点进行,因此当删除根节点后堆原有排列顺序就换遭到破环,因此在删除节点后必须对堆进行调整,整个删除分为两部分,

首先将根节点与末节点进行置换,事根节点处于安全状态,然后将置换后的根节点沿着子节点路径向下转移,知道叶节点处。

private static<T> void adjustHeap(T[]arr,int first,int last,Comparator<? super T> comp)
	{
		int currentPos=first;
		int childPos=2*currentPos+1;
		T target=arr[first];
		while(childPos<last)//易错点
		{
			if(childPos+1<last&&comp.compare(arr[childPos],arr[childPos+1])>0)
			{
				childPos=childPos+1;
			}
			if(comp.compare(arr[currentPos],arr[childPos])>0)
			{
				arr[currentPos]=arr[childPos];
				currentPos=childPos;
				childPos=2*currentPos+1;
			}
			else
			break;
		}
		arr[currentPos]=target;//易错点
	}
	public static<T> T popHeap(T[]arr,int last,Comparator<? super T> comp)
	{
		T temp=arr[0];
		arr[0]=arr[last-1];
		arr[last-1]=temp;
		adjustHeap(arr,0,last-1,comp);
		return temp;
	}


而堆排序则是利用堆每次移除根节点(最大堆曾为最大值)的特点进行排序,因此排序分为两个过程,首先将待排序列进行堆化,然后利用popHeap方法进行排序。

public static<T> void makeHeap(T[] arr,Comparator<? super T> comp)
	{
		int heapPos,lastPos;
		lastPos=arr.length;
		heapPos=(lastPos-2)/2;
		while(heapPos>=0)
		{
			adjustHeap(arr,heapPos,lastPos,comp);
			heapPos--;
		}
	}
	public static <T> void heapSort(T[] arr,Comparator<? super T> comp)
	{
		Heaps.makeHeap(arr, comp);
		int i,n=arr.length;
		for(i=n;i>1;i--)
		{
			Heaps.popHeap(arr, i, comp);
		}
	}

排序的时间复杂度:堆化O(n),pop执行n-1次,因此pop代价为O(log2n),所以总的时间为O(log2n)

与其他诸如快速排序和归并排序不同,堆排序最坏情况复杂度仍然为O(log2n)

 

 

为了更方便的实现倒序与正序排列,可以利用Greater类和Less类,这两个类均实现了Comparator 接口

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值