您的位置:首页 > 其它

堆排序算法及实现

2014-10-26 09:18 309 查看
堆排序分为小根堆(最小堆)和大根堆(最大堆)两种,前一种是升序排列,后一种是降序排列。堆排序与快速排序及归并排序一样,时间复杂度都是O(nlogn),属于比较常用的排序方法。

堆排序是利用了二叉树的特性,二叉堆类似于完全二叉树,小(大)根堆的每一个非叶子节点的值都小于(大于)或等于其左右孩子的值。

堆的存储一般是用数组的形式,i结点的父结点下标是(i-1)/2,左孩子结点下标是2*i+1,右孩子结点下标是2*i+2。数组下标从零开始。

堆排序的过程是一个建堆、删除根和不断调整堆的过程,当然堆的操作还包括插入元素。

整个过程实现如下:

public class HeapSort {
/*
* 方法1: 以需要调整的结点的左孩子为基准,每次判断交换后的非叶子结点
*/
private void adjustHeapNoRec(int[] a, int i, int n) {
int tmp;
tmp = a[i];
int j = 2*i + 1;
while(j < n) {
if(j+1 < n && a[j+1] < a[j]) {
j ++;
}

if(a[j] >= tmp) break;

a[i] = a[j];
i = j;
j = 2*i + 1;
}
a[i] = tmp;
}
/*
* 方法1的递归的处理方法
*/
private void adjustHeapRec(int[] a, int i, int end) {
if(i >= end) return;
int tmp = a[i];
int j = 2*i + 1;
if(j >= end) return;
if(j + 1 < end && a[j+1] < a[j])
j ++;
if(a[j] > a[i]) return;
a[i] = a[j];
i = j;
a[i] = tmp;
adjustHeapRec(a, i, end);
}
/*
* 方法2: 以需要调整的结点为基准,判断其左右孩子,调整到最后一个非叶子节点即可。
*/
private void ajustHeapNonRec(int[] a, int i, int n) {
int min = i;
while(i < (n-1)/2) {
int left = 2*i+1;
int right = 2*i+2;

if(left < n && a[left] < a[min])
min = left;
if(right < n && a[right] < a[min])
min = right;

if(min != i) {
int tmp = a[i];
a[i] = a[min];
a[min] = tmp;
i = min;
}
}
}
/*
* 方法2的递归处理方法
*/
private void adjustHeapRecur(int[] a, int i, int n) {
if(i >= (n-1)/2) return;
int min = i;
int left = 2*i+1;
int right = 2*i+2;
if(left < n && a[left] < a[min])
min = left;
if(right < n && a[right] < a[min])
min = right;
if(min != i) {
int tmp = a[i];
a[i] = a[min];
a[min] = tmp;
adjustHeapRecur(a, min, n);
}
}
/*
* 建堆的过程就是从最后一个非叶子结点开始,不断调整堆的过程。
*/
private void buildHeap(int[] a, int start, int end, int n) {
int mid = (start + end - 1) >> 1;
for(int i = mid; i >= 0; i --) {
// adjustHeapRec(a, i, n);
// ajustHeapNonRec(a,i,n);
adjustHeapRecur(a,i,n);
}
}
/*
* 删除堆:每次删除时,将根与当前堆的最后一个元素交换。
*/
private void deleteHeap(int[] a, int n) {
int j = n - 1;
while(j > 0) {
int tmp = a[0];
a[0] = a[j];
a[j] = tmp;
adjustHeapRec(a, 0, j);
j --;
}
}

public static void main(String[] args) {
int[] a = {3,4,1,5,2};
HeapSort t = new HeapSort();
int n = a.length;
t.buildHeap(a, 0, n-1, n);
t.deleteHeap(a, n);
//输出排序后的数组
boolean flag = true;
for(int i = n-1; i >= 0; i --) {
if(flag) flag = false;
else
System.out.print(" ");
System.out.print(a[i]);
}
System.out.println();
}

}
还有就是向堆中插入一个元素,只需要判断该元素与其父结点的关系,向上调整。
/*
* 插入元素:插入结点i,其父节点的坐标为(i-1)/2
*/
private void insertElem(int[] a, int i) {
int min = i;
while(i > 0) {
int father = (i-1)/2;
if(father >= 0 && a[father] < a[i])
min = father;
if(min == i) {
int tmp = a[i];
a[father] = a[i];
a[i] = tmp;
i = father;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息