堆排序

来源:互联网 发布:八门神器ios源码 编辑:程序博客网 时间:2024/05/18 02:52

有什么不对的地方请指出。

花了大半天时间研究了下堆排序。总体来说堆排序是选择排序和分治思想的结合。每次选择堆顶元素,堆顶元素要么是最大,要么是最小的。分治是指堆进行调整时,每次调整都只会影响一个子树,都使得数据量减少一半。

堆排序的过程:

1.建立堆化数组:从最后一个非叶子节点开始调整,从后往前调整,每次调整后该子树为符合要求的堆,直到i=0的根节点调整完。调整的具体步骤下面介绍

2.把堆顶和堆最后一个位置互换,堆大小减1,这样使堆顶出堆,并对剩余元素进行调整,使之成为大顶堆或者小顶堆

3.重复2操作,直至堆中元素全部出堆。

其中最重要的是堆调整的方法,所有的堆操作都是这个基础上进行的。

堆调整的前提是,左右子树都是符合要求的堆

以大顶堆为例。假设对根节点下标为i(i从0开始,既整个树的根节点下标为0)的子树进行调整,i的左子树根节点为2*i+1,右子树根节点为2*i+2。比较3个节点中值大小,记录最大的节点,若i不是最大节点,把i节点和最大节点互换,并对最大节点为根的子树进行调整(因为互换会破坏子树结构,使之成为非堆结构);若i为最大节点,那就退出该次调整(i节点最大,那么该子树也是大顶堆)。


/**
 * 在左右子树都大顶堆的情况下,进行调整。使用递归调用。
 * 
 * @param a
 *            堆数组
 * @param i
 *            要调整的子树根节点号。(以0开始,子节点分别为2*i+1, 2*i+2)。
 * @param size
 *            整个堆的大小。
 */

public static void maxHeapAdjust(int[] a, int i, int size) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int max = i;                         // 记录这次调整的最大数节点号。
if (i < size / 2) {                  // i是非叶子节点,就不要调整了。
if (left < size && a[max] < a[left])
max = left;
if (right < size && a[max] < a[right])
max = right;
if (max != i) {
swap(a, i, max);
maxHeapAdjust(a, max, size);
}
}
}



堆排序的完整代码如下:

public class HeapSort {

public static void main(String[] args) {
int[] a = new int[] { 3, 4, 5, 9, 10,2, 6, 7 };
print(a);
System.out.println("+++++++++排序前+++++++++++++");
minHeapSort(a);
System.out.println("+++++++++排序后+++++++++++++");
print(a);
}

public static void maxHeapSort(int[] a) {
int size = a.length;
if(size <= 1)
return ;


// 建立堆化数组
for (int i = (size-2)/2; i >= 0; i--) {
maxHeapAdjust(a, i, size);
}


// 进行堆排序
for (int i = size - 1; i >= 0; i--) {
swap(a, 0, i);
maxHeapAdjust(a, 0, i);
}
}


public static void minHeapSort(int[] a) {
int size = a.length;
if(size <= 1)
return ;


// 建立堆化数组
for (int i = (size-2)/2; i >= 0; i--) {
minHeapAdjust(a, i, size);
}

// 进行堆排序
for (int i = size - 1; i >= 0; i--) {
swap(a, 0, i);
minHeapAdjust(a, 0, i);
}
}


/**
* 在左右子树都大顶堆的情况下,进行调整。使用递归调用。

* @param a
*            堆数组
* @param i
*            要调整的子树根节点号。(以0开始,子节点分别为2*i+1, 2*i+2)。
* @param size
*            整个堆的大小。
*/
public static void maxHeapAdjust(int[] a, int i, int size) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int max = i;                  // 记录这次调整的最大数节点号。
if (i < size / 2) {            // i是非叶子节点,就不要调整了。
if (left < size && a[max] < a[left])
max = left;
if (right < size && a[max] < a[right])
max = right;
if (max != i) {
swap(a, i, max);
maxHeapAdjust(a, max, size);
}
}
}

/**
* 在左右子树都小顶堆的情况下,进行调整。使用递归调用。

* @param a
*            堆数组
* @param i
*            要调整的子树根节点号。(以0开始,子节点分别为2*i+1, 2*i+2)。
* @param size
*            整个堆的大小。
*/
public static void minHeapAdjust(int[] a, int i, int size) {


int left = 2 * i + 1;
int right = 2 * i + 2;
int min = i;                       // 记录这次调整的最大数节点号。
if (i < size / 2) {                 // i是非叶子节点,就不要调整了。
if (left < size && a[min] > a[left])
min = left;
if (right < size && a[min] > a[right])
min = right;
if (min != i) {
swap(a, i, min);
minHeapAdjust(a, min, size);
}
}
}


private static void swap(int[] a, int i, int j) {
int temp = a[j];
a[j] = a[i];
a[i] = temp;
}


private static void print(int[] a) {
for (int i : a) {
System.out.print(i + " , ");
}
System.out.println();
}
}

0 0
原创粉丝点击