堆排序

堆排序中用到的是二叉堆,它其实就是一棵近似于完全二叉树树按照层次遍历得到的数组。而堆排序中只要是利用最大(小)堆来完成的。最大(小)堆其实就是满足在父亲节点、左孩子、右孩子中父亲点是最大(小)值的堆。显然,根节点的左子树与右子树也可以看成最大(小)堆。而优先队列算是堆排序算法的一个典型应用,文章后面也会讲到。

排序过程

排序的算法如下:

HEAPSORT(A)
//将带排序的数组A构建成最大堆,A的起始下标为0
1.BUILD-MAX-HEAP(A)
//每次从堆中取出最大的元素,然后与堆最末尾的元素交换,并将此元素从堆中提出,再更新堆的状态维持
其最大堆的性质,知道堆的元素只有一个位置,排序就结束了。
2.for i=A.length-1 downto 1
3.  exchangeA[1] with A[i]
4.  A.heapsize=A.heapsize-1
5.  UPDATEMAXHEAP(A,0)
BUILD-MAX-HEAP(A)
1.  A.heapsize=A.length
2.  for i=A.length/2 downto 1
3.      UPDATEMAXHEAP(A,i)
UPDATEMAXHEAP(A,i)
1.  left=2*i+1  //找到i的左孩子
2.  right=2*i+2     //找到i的右孩子
//找到i,i的左孩子、右孩子三者中的最大值所在位置largest。
3.  if left<=A.heapsize and A[left]>A[i]
4.      largest=left
5.  else lagerst=i;
6.  if r<=A.heapsize and A[r]>A[largest]
7.      largest=r
8.//最大值A[largest]放到父亲节点i的位置
8.  if largest!=i //递归结束条件
9.      exchange A[i]with A[largest]
10.     UPDATEMAXHEAP(A,largest)

从这里可以总结出堆排序的最重要两个步骤就是:1.构建最大(小)堆。2.更新堆,保证最大(小)堆的性质

堆代码如下:

/**

 * @author CoderGang

 * 堆排序的实现

 */

public class HeapSort {



    /**

     * 根据数组对象构造最大堆

     * @param arry,数组对象

     */

    private void buildMaxHeap(int[] arry ){

        for(int i= (arry.length>>1)-1;i>=0;i--){

            //updateMaxHeapRecursive(arry,i,arry.length);

            updateMaxHeapLoop(arry,i,arry.length);

        }

    }

    /**

     * 更新堆的状态,非递归版本

     * @param heap 堆

     * @param parent 父亲结点

     * @param heapSize 堆的大小

     */

    private void updateMaxHeapLoop(int[] heap,int parent,int heapSize){

        int right = (parent << 1) + 2;

        int left = (parent << 1) + 1;

        int largest;



        while (true){

            if (left heap[parent]) {

                largest = left;

            } else {

                largest = parent;

            }



            if (right heap[largest]) {

                largest = right;

            }

            if (largest != parent) {

                int tmp = heap[largest];

                heap[largest] = heap[parent];

                heap[parent] = tmp;

            }else {

                break;

            }

            right=(largest<<1)+2;

            left=(largest<<1)+1;

            parent=largest;

            if(right>=heapSize && left>=heapSize) {

                break;

            }



        }

    }



    /**

     * 更新堆的状态,递归版本

     * @param heap 堆

     * @param parent 父亲结点

     * @param heapSize 堆的大小

     */

    private void updateMaxHeapRecursive(int[] heap,int parent,int heapSize) {

        int right = (parent << 1) + 2;

        int left = (parent << 1) + 1;

        int largest;



        if (left heap[parent]) {

            largest = left;

        } else {

            largest = parent;

        }



        if (right heap[largest]) {

            largest = right;

        }

        if (largest != parent) {

            int tmp = heap[largest];

            heap[largest] = heap[parent];

            heap[parent] = tmp;

            //updateMaxHeapRecursive(heap, largest,heapSize);

            updateMaxHeapRecursive(heap, largest,heapSize);

        }

    }



    /**

     * 对数组进行排序

     * @param arry,要排序的数组

     */

    public void sort(int[] arry) {

        buildMaxHeap(arry);

        int heapSize=arry.length;

        for(int i=arry.length-1;i>0;i--){

            int tmp=arry[i];

            arry[i]=arry[0];

            arry[0]=tmp;

            heapSize--;

            //updateMaxHeapRecursive(arry,0,heapSize);

            updateMaxHeapLoop(arry, 0,heapSize);

        }

        for (int i:arry) {

            System.out.print(i+" ");

        }

    }

    public static void main(String [] args) {

       int []a=/*{1,2,3,4,5};*/{1,5,8,3,4,14,9,86,54,1654,15,45,6,13,45,16,4,78,9,1,3,4,8,4,64,748915};

       new HeapSort().sort(a);

    }
}

你可能感兴趣的:(堆排序)