堆排序(heapsort)

堆排序的运行时间为Θ(nlgn),它是一种原地排序算法:在任何时候,数组中只有常数个元素存储在输入数组以外;

对数据结构是一种数组对象,它可以被视为一棵完全二叉树。树中得每个结点与数组中存放该结点值的那个元素对应。

树的每一层都是填满的,最后一层可能除外,表示堆的数组A是一个具有两个属性的对象:length[A]是数组中的元素

个数,heap-size[A]是存放A中的堆元素个数。

给定某个结点的下标 i , 其父结点PARENT(i),左儿子LEFT(i)和右儿子RIGHT(i)的下标可以计算出来:

PARENT(i)

  return i/2

LEFT(i)

  return 2 * i

RIGHT(i)

  return 2 * i + 1

最大堆是指除了根以外的每个结点 i,有 A[PARENT(i)] >= A[i]

最小堆是指除了根以外的每个结点 i,有 A[PARENT(i)] <= A[i]

在堆排序算法中使用的是最大堆。

保持堆的性质  MAX- HEAPIFY 过程:

MAX-HEAPIFY(A, i)
  l ← LEFT(i)
  r ← RIGHT(i)
  if l <= heap-size[A] and A[l] > A[i]
    then largest ← l
    else largest ← i
  if r <= heap-size[A] and A[r] > A[largest]
    then largest ← r
  if largest != i

    then exchange A[i] ↔ A[largest]
      MAX-HEAPIFY(A, largest)

BUILD-MAX-HEAP过程:

BUILD-MAX-HEAP(A)
  heap-size(A) ← length[A]
  for i ← length[A]/2 downto 1
    do MAX-HEAPIFY(A, i)

堆排序算法:

HEAPSORT(A)
  BUILD-MAX-HEAP(A)
  for i ← length[A] downto 2
    do exchange A[1] ↔ A[i]
      heap-size[A] ← heap-size[A] - 1
      MAX-HEAPIFY(A, 1)

Java实现

    public void heapSort(int[] a)
    {
        int heapSize = a.length;
        buildMaxHeap(a);
        for (int i = a.length - 1; i > 0; i--)
        {
            swap(a, 0, i);
            maxHeapify(a, 0, --heapSize);
        }
    }
    
    private void buildMaxHeap(int[] a)
    {
        for (int i = a.length / 2; i >= 0; i--)
        {
            maxHeapify(a, i, a.length);
        }
    }
    
    private void maxHeapify(int[] a, int i, int heapSize)
    {
        int largest = 0;
        int l = 2 * i + 1;
        int r = 2 * i + 2;
        if (l < heapSize && a[l] > a[i])
        {
            largest = l;
        }
        else
        {
            largest = i;
        }
        if (r < heapSize && a[r] > a[largest])
        {
            largest = r;
        }
        if (largest != i)
        {
            swap(a, i, largest);
            maxHeapify(a, largest, heapSize);
        }
    }
    
    private void swap(int[] data, int src, int des)
    {
        int tmp = data[des];
        data[des] = data[src];
        data[src] = tmp;
    }

用Java实现伪码需要注意

1.数组的下标:

  • 大于1还是大于0,等等
  • 因为Java的数组下标是从0开始,与伪码对应的结点 i 左孩子右孩子的下标分别是2*1+1, 2*i+2.

2.maxHeapify需要一参数heapSize是因为在heapSort交换后,要从堆中去掉此元素结点(此时去掉的元素结点就是堆中的最大结点)

3.堆排序是分3个过程来完成,在最后验证堆排序的实现是否正确,先测试验证maxHeapify正确,然后是建堆buildMaxHeap正确,最后验证

堆排序是否正确。否则一开始就验证堆排序,出了问题就不知道到底是哪个过程出错。

原文地址:https://www.cnblogs.com/zhuqiang/p/2485943.html