堆排序

堆排序

堆排序时间复杂度为O(nlgn),且具有空间原址性,只需要常数个额外的元素空间存储临时数据。但堆排序是不稳定的算法,即对相等的两个元素,排序后不能保证他们的顺序与原始数据的顺序相同。

1.堆

堆是一个数组,可以把它看成一个近似的完全二叉树。树上的每一个结点对应数组中的一个元素,除最底层外,该树是完全充满的,而且是从左向右填充。
堆数组有两个和堆排序相关的重要属性,数据元素的个数(length)和堆元素(heapSize)。可以理解为数组中只有一部分数据用来表示当前堆,因此 0 <= heapSize <= length。
编程时,堆的根节点在数组中的索引值为0。对给定的某个节点的索引i,其父结点、左孩子和右孩子可以计算得出:
  parent(i) = (i - 1) >> 1;
  left(i) = (i << 1) + 1;
  right(i) = (i << 1) + 2;
堆又分为最大堆和最小堆。在最大堆中,根节点的值不小于它的任意一个子节点,即最大元素存在根节点中。在最小堆中,根节点不大于它的任意一个子节点,即最小元素存在根节点中。

2.维护堆的性质

维护堆的性质是维护最大堆或最小堆的重要过程,维护最大堆或最小堆需要多次使用此方法。以最大堆为例,其算法如下:
  maxHeapify(a, i, heapSize)
    l = left(i);
    r = right(i);
    largest = i;
    if l < heapSize and a[largest] < a[l]
      largest = l;
    if r < heapSize and a[largest] < a[r]
      largest = r;
    if largest != i
      exchange(a[largest], a[i])
      maxHeapify(a, largest, heapSize)
程序中a[i],a[l],a[r]中选出最大的,并将其下标存储在largest中。如果a[i]是最大的,那么以i为根的结点的子树已经是最大堆。否则,最大元素是i的某个子结点,则交换a[i]与a[largest]的值,从而使i及其孩子满足最大堆的性质。在交换后,下标为largest的结点的值是原来的a[i],于是以该结点为根的子树有可能违反最大堆的性质,需要对该子树递归调用maxHeapify方法。

3.建堆

建堆即建立最大堆或最小堆。需要用到maxHeapify方法。其算法如下
  buildMaxHeap(a)
    heapSize = a.length;
    for i = (a.length >> 2) downto 0
      maxHeapify(a, i, heapSize)

4.堆排序算法

(1)利用buildMaxHeap将输入的数组建立为最大堆
(2)因为最大堆中的第一个元素为最大值,因此可以把它与最后一个位置交换,这时候最大值即被排到最后
(3)但由于第一个元素改变,需要重新维护堆的性质,此时最后一个元素已排好序,去掉最后一个元素(heapSize减1)再次对第一个元素维护堆的性质即可
(4)反复执行过程(2)~(3),直到第二个元素,就完成了堆排序。
  sort(a)
    buildMaxHeap(a)
    for i = a.length - 1 downto 1
      exchange(a[0], a[i])
      maxHeapify(a, 0, i)

 

java算法实现

package com.diysoul.algorithm.sort;

import java.util.Random;

public class HeapSort {

    public static void sort(int[] a) {
        buildMaxHeap(a);
        for (int i = a.length - 1; i > 0; i--) {
            int temp = a[0];
            a[0] = a[i];
            a[i] = temp;
            maxHeapify(a, 0, i);
        }
    }

    public static void buildMaxHeap(int[] a) {
        int heapSize = a.length;
        for (int i = a.length >>> 1; i >= 0; i--) {
            maxHeapify(a, i, heapSize);
        }
    }

    public static void maxHeapify(int[] a, int i, int heapSize) {
        int l = (i << 1) + 1;
        int r = (i << 1) + 2;
        int largest = i;
        if (l < heapSize && a[largest] < a[l]) {
            largest = l;
        }
        if (r < heapSize && a[largest] < a[r]) {
            largest = r;
        }
        if (largest != i) {
            int temp = a[i];
            a[i] = a[largest];
            a[largest] = temp;

            // print(a);
            maxHeapify(a, largest, heapSize);
        }
    }

    public static void main(String[] args) {
        int maxSize = 1000;
        int min = 0;
        int max = 1000;
        Random random = new Random();

        int[] a = new int[maxSize];
        for (int i = 0; i < a.length; i++) {
            a[i] = random.nextInt(max - min) + min;
        }
        print(a);
        sort(a);
        print(a);
        checkSort(a);
    }

    private static void checkSort(int[] array) {
        if (array == null || array.length == 0)
            return;
        for (int i = 1; i < array.length; i++) {
            if (array[i - 1] > array[i]) {
                System.out.println("Error! Array is not sorted in index " + i);
                break;
            }
        }
    }

    private static void print(int[] array) {
        if (array == null || array.length == 0)
            return;
        System.out.print("heap sort array(" + array.length + "): ");
        int i = 0;
        for (; i < array.length - 1; i++) {
            System.out.print(array[i] + ", ");
        }
        System.out.println(array[i]);
    }
}

 

posted @ 2016-07-14 17:32  阿Hai  阅读(224)  评论(0编辑  收藏  举报