堆排序
堆排序(Heap Sort),顾名思义,借助于堆的形式来实现排序。这个堆分为大根堆和小根堆两种,大根堆用来实现从小到大的顺序排序,小根堆则用来实现从大到小的降序排序。每构造出一个大(小)根堆,即获得了一个最优值(根节点),将该根节点去掉,剩余的继续进行构造堆的做法,获得剩余元素的最优值,重复之前的做法,直到全部完成排序为止。
堆排序的难点即在于堆的构成和实现。以大根堆为例,先将一个无序队列看做一个堆。其中,坐标 0 元素为根元素,1、2坐标元素为 0 元素的子元素,3、4坐标元素为 1 元素的子元素,5、6坐标元素为 2 坐标的子元素,以此类推。然后,从根堆的最底端子节点(非叶子节点),也即中间节点开始分别与其子节点进行比较,将其中的大者作为该子节点的元素。逐个排查所有的非叶子节点,直到根节点为止,将最大元素赋给根节点。这样经过排查,即找到了堆的最大值。将该最大值与堆的末端节点对换,重复上述过程,对剩余的元素重新进行堆的构造和最优值的对换,直到全部排序完成为止。
Java代码如下:
/**
* 大根堆排序:实现顺序排序
* @param data
* @param i
*/
private static void heapSort(int[] data, int length) {
//递归结束
if (1 == length) {
return;
}
//获取最底端的非叶子节点的坐标
int mid = (length -1)>>1;
//构造堆
//左右子节点的坐标
int left = 0;
int right = 0;
for (int i = mid; i >= 0; i--) {
//与左孩子节点比较
left = (i+1)<<1;
if (left<=length && data[i]<data[left]) {
swap(data,i,left);
}
//与右孩子节点比较
right = left -1;
if (right<=length && data[i]<data[right]) {
swap(data,i,right);
}
}
//将最大值与队列最后一个元素对换
swap(data, 0, length);
//递归上面的过程
heapSort(data, length - 1);
}
/**
* 数组内 i 坐标元素与 j 坐标元素互换
* @param data
* @param i
* @param j
*/
private static void swap(int[] data, int i, int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
该算法的初始参数为数据data和数据末点坐标 data.length-1。因为只有最底端的非叶子节点的叶子节点有可能出现越界情况,因此,这里可以做一点改进,减少不必要的越界判断。
代码如下:
/**
* 大根堆排序:实现顺序排序
* @param data
* @param i
*/
private static void heapSort2(int[] data, int length) {
//递归结束
if (1 == length) {
return;
}
//获取最底端的非叶子节点的坐标
int mid = (length -1)>>1;
//构造堆
//左右子节点的坐标
int left = 0;
int right = 0;
//最底端的非叶子节点比较
int i = mid;
left = (i+1)<<1;
if (left<=length && data[i]<data[left]) {
swap(data,i,left);
}
right = left -1;
if (right<=length && data[i]<data[right]) {
swap(data,i,right);
}
i--;
//剩余非叶子节点比较
for (; i >= 0; i--) {
//与左孩子节点比较
left = (i+1)<<1;
if (data[i]<data[left]) {
swap(data,i,left);
}
//与右孩子节点比较
right = left -1;
if (data[i]<data[right]) {
swap(data,i,right);
}
}
//将最大值与队列最后一个元素对换
swap(data, 0, length);
//递归上面的过程
heapSort(data, length - 1);
}
/**
* 数组内 i 坐标元素与 j 坐标元素互换
* @param data
* @param i
* @param j
*/
private static void swap(int[] data, int i, int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}