算法:堆排序


堆排序可归纳为两个操作:

1)建堆:根据初始数组去构造初始堆(构建一个完全二叉树,保证所有的父结点都比它的孩子结点数值大)。

2)调整堆:每次交换第一个和最后一个元素,输出最后一个元素(最大值),然后把剩下元素重新调整为大根堆。 当输出完最后一个元素后,这个数组已经是按照从小到大的顺序排列了。调整堆的过程是:比较节点i和左右节点,选出三者最大的,如果是孩子节点,那么交换;并继续比较。

建大根堆:buildMaxHeap(a[])

从A.length / 2一直到根结点进行堆调整。

堆调整:adjustHeap(a[], parent, length);

  • 定义左孩子child = 2 * parent + 1;tmp保存父节点;
  • 当child < length 的时候:
    • 如果有右孩子并且右孩子大于左孩子,则选取右孩子;(选择孩子中较大的;)
    • 如果父节点值>孩子节点 break;(父>子,调整完毕;)
    • 孩子节点的值赋给父节点;(调整父和孩子;)
    • 孩子index赋给父index;并继续child的孩子index赋给孩子index(继续向下调整;)
  • tmp赋给最后的父节点;(找到调整值得最终位置;)

堆排序:heapSort(a[])

  • 建最大堆;
  • for(i=n-1)循环n-1次,交换首尾;adjustHeap(a, 0, i);

辅助交换:swap(a[], i, j)

参考代码:

public class Solution {
    /**
     * @param A an integer array
     * @return void
     */
     //堆排序
    public void sortIntegers(int[] a) {
        if (a.length == 0) return;
        buildMaxHeap(a);
        for (int i = a.length - 1; i > 0; i--) {
            swap(a, i, 0);
            adjustHeap(a, 0, i);
        }
    }
    
    public void buildMaxHeap(int[] a) {
        for (int i = a.length/2; i >= 0; i--) {
            adjustHeap(a, i, a.length);
        }
    }
    
    
    public void adjustHeap(int[] a, int parent, int length) {
        int tar = a[parent];
        int child = parent * 2 + 1;
        while (child < length) {
            if (child + 1 < length && a[child] < a[child + 1]) child++;
            if (a[child] < tar) break;
            a[parent] = a[child];
            parent = child;
            child = child * 2 + 1;
        }
        a[parent] = tar;
    }
    
    public void swap (int[] a, int i, int j) {
        int tmp = a[i];
        a[i] = a[j];
        a[j] = tmp;
    }
    
}
  • adjustHeap(a, parent, length):
    • tar值保存a[parent];定义child;
    • 当chile<length:
      • 获取左右孩子中较大的:若存在右孩子且大于左孩子则child++;
      • 比较child和tar:若已经满足[tar]>[child]则break;
      • child值赋给parent:注意这里是赋值而不是swap;
      • 继续向下调整:parent变化,child变化;
    • tar值赋给最终的a[parent];
  • buildMaxHeap(a):
    • for(i=a.length/2; i>=0),adjustHeap(a,i,a.length);注意参数是length;循环范围是[0,a.length/2];
  • heapSort(a):
    • 判断空return;
    • 建堆buildHeap(a);
    • 循环n-1次调整堆for(i=a.length-1; i>0); 循环范围是(0,length-1]n-1次;
      • swap(a,i,0);
      • adjustHeap(a,0,i) length的范围是[0,n-1]也就是i;
  • swap(a[],i,j);

参考:堆排序

测试数据:LintCode--Sort Integers 


原文地址:https://www.cnblogs.com/buwenyuwu/p/7219576.html