排序算法之堆排序

 

Posted by DH on August 6, 2017

思想

堆排序在排序算法中属于比较难的一个了,首先阐明一些概念。

堆的实质是一颗完全二叉树,假如一颗二叉树的层数的h,那么这可二叉树的h-1层都是满二叉树。

假如堆中的父节点的值<子节点的值,这个堆叫做小根堆

假如堆中的父节点的值>子节点的值,这个堆交大根堆。

而数组与堆的对应是顺序对应,堆就是顺序存储的二叉树,如下图所示:

堆排序的主要步骤是;

将数组Array[0]…..Array[n]构造成堆。

交换array[0] 和 array[n].将array[0]….array[n-1]构造成堆。

不断循环,直到交换了array[0]和array[1].

可以归纳为两个操作;

(1)构造堆(根据数组,构造堆)

(2)每次交换第一个和最后一个元素,输出最后一个元素(最大值),然后把剩下元素重新调整为大根堆或小根堆。

例子

构建堆的过程:

排序的过程:

代码

package test;

import java.util.Arrays;

public class HeapSort {
		public static void main(String[] args) {
			HeapSort heapSort = new HeapSort();
			int[] array = {1, 3, 4, 5, 2, 6, 9, 7, 8, 0};
			heapSort.heapSort(array);
			System.out.println(Arrays.toString(array));
		}
  
	// 构造初始堆
	public void adjustHeap(int [] array,int parentIndex,int length){
		
		// 孩子节点的索引
		int childIndex = parentIndex * 2 + 1;
		
		while (childIndex < length) {
			
			
			// 如果有右孩子,选出孩子节点最大的
			if (childIndex + 1 < length && array[childIndex] < array[childIndex + 1]) {
				childIndex ++;
			}
			
			// 如果父节点大于孩子节点,直接退出,不用进行下一步
			if (array[childIndex] < array[parentIndex]) {
				break;
			}else{
				
				// 把孩子节点的值和父节点的值进行交换
				int temp = array[parentIndex];
				array[parentIndex] = array[childIndex];
				array[childIndex] = temp;
				
				parentIndex = childIndex;
				childIndex = parentIndex * 2 +1;
			}
			
		}
	}
	
	public void heapSort(int [] array) {
		// 构造初始堆
		for(int i = array.length /2; i >= 0;i--){
			adjustHeap(array, i, array.length);
		}
		
		// 循环n-1次,每次都将第一个节点和最后一个节点交换
		for(int j = array.length - 1; j>0; j--){
			int temp = array[0];
			array[0] = array[j];
			array[j] = temp;
			
			// 调整剩下的j-1个元素的堆
			adjustHeap(array, 0,j);
			
		}
		
	}
	
}