0
点赞
收藏
分享

微信扫一扫

排序算法-堆排序

是她丫 2022-03-11 阅读 76

在学堆排序之前得先明白什么是完全二叉树。

完全二叉树就是从上到下,从左到右中间没有间隔的二叉树。

例如

这样可以称为完全二叉树,

这样就不行了,

那么在了解了什么是完全二叉树之后,我们就可以把数组展开成一个完全二叉树。

就像这样。

我们再来了解一个概念【大根堆】

大根堆就是父节点是要大于子节点的,左右兄弟节点没有要求。

那么一个数组如何转化为大根堆呢?

例如数组{1,4,3,2,7,9},我们假设从数组中一个一个数拿出来进行大根堆。

先拿出来1,就一个数肯定满足大根堆

4进来的时候,不满足大根堆,所以需要交换1和4

然后3再进来

满足大根堆,继续。

2进来之后不满足大根堆,交换1和2

 然后再7进来,同样不满足大根堆,继续交换。

交换一次之后任然不满足大根堆,7继续交换

后面的都是一样操作的。代码如下

	public static void heapInsert(int[] arr,int index) {
		while(arr[index]>arr[(index - 1)/2]) {//父节点的位置为(i-1)/2
			swap(arr,index,(index-1)/2);
			index = (index-1)/2;
		}
		
	}

这是来了一个数要往二叉树的上面走的,那如果是需要往下面走的又是怎样的呢?

	//判断是否继续往下走
	public static void heapify(int[] arr,int index,int heapSize) {
		int left = index * 2 + 1;//左孩子
		while(left<heapSize) {
			//左孩子要在heapSize范围之内,在进行排序时,范围之外的都是已经排好序的了。
			int largest = left + 1<heapSize && arr[left+1] > arr[left]? left+1:left;
			//先找左右孩子中最大的那个,右孩子要最大,要满足右孩子存在且比左孩子大。
			largest = arr[largest] > arr[index] ? largest : index;
			//孩子中的最大值来和父节点对比。
			if(largest == index) {
			//如果最大的就是父节点,那么就不需要进行换位
				return ;
			}
			//如果最大是子节点,那么就需要更换值,并继续进行下一轮的判断。
			swap(arr,largest,index);
			index = largest;
			left = index * 2 + 1;
		}
		
		
	}

那这个东西有什么用呢?

假设一个数组满足大根堆,那么根节点一定就是最大的值,

让根节点和最后一个节点交换,那么数组最后一个元素就是最大值了,

然后让根节点进行从上往下走,直到满足大根堆,然后再让根节点跟数组的倒数第二个元素进行交换,

这样循环下来,最终数组就是有序的了。

	public static void heapSort(int[] arr) {
		if(arr == null || arr.length<2) {
			return ;
		}
		
		//效率较低
		for(int i = 0;i<arr.length;i++) {
			heapInsert(arr,i);
		}
		//变成大根堆
		
		//效率较高
//		for(int i=arr.length-1;i>0;i--) {
//			heapify(arr,i,arr.length);
//		}
		//从最后一个元素开始往上走,最终也能够成为大根堆。
		int heapSize = arr.length;
		swap(arr,0,--heapSize);
		//heapSize表示二叉树的范围,一旦确定了在数组中的位置,就不再划分到二叉树去了
		while(heapSize>0) {
			heapify(arr, 0, heapSize);
			swap(arr,0,--heapSize);
		}
	}
举报

相关推荐

0 条评论