堆排序是使用二叉树模型,建立最大堆或最小堆,将最大值或最小值上浮,降低遍历次数,增加排序效率的一种解决方法。
由于堆排序时使用的是完全二叉模型,所以可以使用数组进行表示。
在使用堆排序时,需要使用到完全二叉树的一些公式,如父节点n/2-1,左子节点2i+1,右子节点2i+2,叶子节点(>size/2)等。具体见代码。
1、首先定义堆模型的一些常用操作接口。
package cn.dream.sort;
public interface IHeapSort {
/**
* 获取父节点的位置
* 完全二叉树父节点位置在(n-1)/2处
* @param i
* @return
*/
int getParent(int i);
/**
* 获取左子位置
* 完全二叉树左子节点在2*i+1处
* @param i
* @return
*/
int getLeftChild(int i);
/**
* 获取右子位置
* 完全二叉树右子节点在左子节点的后面(2*i+1)+1
* @param i
* @return
*/
int getRightChild(int i);
/**
* 建堆
* 从n/2-1处开始调整树结构,因为从n/2处都是叶子节点,不需要调整
* @param a
* @param size
*/
int[] buildHeap(int[] a, int size);
/**
* 调整堆
* 通过对堆的调整,使其满足堆结构的要求,最大值上浮或最小值上浮。
* 对于任一节点进行调整时:
* 1、最大堆:如果该节点比(左右子节点最大值)小,交换该节点和最大值位置,然后调整树
* 2、最小堆:如果该节点比(左右子节点最小值)大,交换该节点和最小值位置,然后调整树
* @param a
* @param i
* @param size
*/
int[] adjustHeap(int[] a, int i, int size);
/**
* 堆排序
* 1、最小堆:
* 方法一:执行遍历{将根节点(min)取出,构建树}
* 方法二:执行遍历{将根节点(min)和最后一个节点(数组最后一位)交换,将参与构建的数组长度-1(移动size的index),重新构建树结构},最后倒序输出
* 2、最大堆:执行遍历{将根节点(max)和最后一个节点(数组最后一位)交换,将参与构建的数组长度-1(移动size的index),重新构建树结构}
* @param a
* @param size
*/
int[] sortHeap(int[] a, int size);
}
然后分别建立最大堆和最小堆,进行编码测试
最小堆
package cn.dream.sort;
import java.util.Arrays;
public class MinHeapSortImpl implements IHeapSort {
@Override
public int getParent(int i) {
return (int) (i - 1) / 2;
}
@Override
public int getLeftChild(int i) {
return 2 * i + 1;
}
@Override
public int getRightChild(int i) {
return 2 * i + 2;
}
@Override
public int[] buildHeap(int[] a, int size) {
for (int i = (size - 2) / 2; i >= 0; i--) {
adjustHeap(a, i, size);
}
return a;
}
@Override
public int[] adjustHeap(int[] a, int i, int size) {
int min = i;
int temp = a[i];
int left = getLeftChild(i);
int right = getRightChild(i);
if (left < size && a[left] < temp) {
min = left;
}
if (right < size && a[right] < a[min]) {
min = right;
}
if (min != i) {
a[i] = a[min];
a[min] = temp;
adjustHeap(a, min, size);
}
return a;
}
@Override
public int[] sortHeap(int[] a, int size) {
int[] b = new int[a.length];
int i = 0;
while(size>0) {
b[i] = a[0];
a[0] = a[size - 1];
--size;
adjustHeap(a, 0, size);
i++;
}
return b;
}
public static void main(String[] args) {
int[] arr = { 53, 4, 24, 47, 41, 97, 13, 83, 12, 35, 11, 15, 41, 18,
68, 49, 36, 52, 9, 45, 0, 38, 36, 82, 76, 22, 44, 35, 34, 81,
94, 70, 88, 30, 42, 45, 55, 75, 93, 57, 74, 0, 77, 64, 93, 58,
15, 62, 13, 49, 60, 21, 3, 66, 15, 74, 48, 96, 52, 56, 63, 73,
85, 44, 39, 42, 98, 38, 17, 81, 7, 60, 86, 79, 63, 66, 17, 78,
78, 90, 23, 92, 79, 21, 80, 71, 6, 70, 59, 25, 41, 11, 64, 60,
62, 51, 93, 46, 18, 31 };
long startTime = System.currentTimeMillis();
IHeapSort heapSort = new MinHeapSortImpl();
System.out.println("测试最小堆的根节点是否最小值:");
heapSort.buildHeap(arr, arr.length);
System.out.println("root is:" + arr[0]);
System.out.println("测试最小堆是否已经排序:");
System.out.println(Arrays.toString(arr));
System.out.println("排序:");
int[] heap = heapSort.sortHeap(arr, arr.length);
System.out.println(Arrays.toString(heap));
System.out.println((System.currentTimeMillis() - startTime) + "ms");
}
}
最大堆
package cn.dream.sort;
import java.util.Arrays;
public class MaxHeapSortImpl implements IHeapSort {
@Override
public int getParent(int i) {
return (int) (i - 1) / 2;
}
@Override
public int getLeftChild(int i) {
return 2 * i + 1;
}
@Override
public int getRightChild(int i) {
return 2 * i + 2;
}
@Override
public int[] buildHeap(int[] a, int size) {
for (int i = (size - 2) / 2; i >= 0; i--) {
adjustHeap(a, i, size);
}
return a;
}
@Override
public int[] adjustHeap(int[] a, int i, int size) {
int largest = i;
int temp = a[i];
int left = getLeftChild(i);
int right = getRightChild(i);
if (left < size && a[left] > temp) {
largest = left;
}
if (right < size && a[right] > a[largest]) {
largest = right;
}
if (largest != i) {
a[i] = a[largest];
a[largest] = temp;
adjustHeap(a, largest, size);
}
return a;
}
@Override
public int[] sortHeap(int[] a, int size) {
// buildHeap(a, size);
int temp;
for (int i = size - 1; i >= 0; i--) {
temp = a[0];
a[0] = a[i];
a[i] = temp;
adjustHeap(a, 0, i);
}
return a;
}
public static void main(String[] args) {
int[] arr = { 53, 4, 24, 47, 41, 97, 13, 83, 12, 35, 11, 15, 41, 18,
68, 49, 36, 52, 9, 45, 0, 38, 36, 82, 76, 22, 44, 35, 34, 81,
94, 70, 88, 30, 42, 45, 55, 75, 93, 57, 74, 0, 77, 64, 93, 58,
15, 62, 13, 49, 60, 21, 3, 66, 15, 74, 48, 96, 52, 56, 63, 73,
85, 44, 39, 42, 98, 38, 17, 81, 7, 60, 86, 79, 63, 66, 17, 78,
78, 90, 23, 92, 79, 21, 80, 71, 6, 70, 59, 25, 41, 11, 64, 60,
62, 51, 93, 46, 18, 31 };
long startTime = System.currentTimeMillis();
IHeapSort heapSort = new MaxHeapSortImpl();
System.out.println("测试最大堆的根节点是否最大值:");
heapSort.buildHeap(arr, arr.length);
System.out.println("root is:" + arr[0]);
System.out.println("测试最大堆的顺序是否为倒序:");
System.out.println(Arrays.toString(arr));
System.out.println("排序:");
heapSort.sortHeap(arr, arr.length);
System.out.println(Arrays.toString(arr));
System.out.println((System.currentTimeMillis() - startTime) + "ms");
}
}
更多排序,,参考这位的http://blog.csdn.net/han_xiaoyang/article/details/12163251