学习堆排序

Posted xjz1842

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了学习堆排序相关的知识,希望对你有一定的参考价值。

  首先,看一下堆的定义;

  n个元素的序列{k1,k2,…,kn}当且仅当满足下列关系之一时,称之为堆。

  情形1:k<= k2i 且k<= k2i+1 最小化堆小顶堆

  情形2:k>= k2i 且k>= k2i+1 (化堆大顶堆

  其中i=1,2,…,n/2向下取整;            

      该排序的思想是;首先建立二叉堆,这个阶段花费O(N)时间,然后我们执行N次deleteMin操作。按照顺序,最小的元素先离开堆,通过将这些元素记录到第二数组,最后在将数组拷贝回来,得到N个元素的顺序,由于每个deleteMIn花费时间O(logN), 因此,总的运行时间是O(NlogN). 优先队列,可以用于O(NlogN)时间排序, 基于该思想的算法叫做堆排序。

     该算法的主要问题是使用一个附加的数组,一次存储需求增加一倍,为了回避使用第二个数组的,可以在每次deleteMin之后,堆缩减1,因此,位于堆中左后的单元,可以存储刚刚存放删除的元素。使用这种策略,该数组将以递减的的顺序包含这些元素.

      java代码的例子:

   

public class HeapSort {

    public static void main(String[] args) throws Exception{
        Integer [] a  = new Integer[]{32,12,345,5,66,23};
        heapSort(a);

        Arrays.stream(a).forEach(System.out::println);
    }

    /**
     * Internal method for heapSort that is used in  deleteMax and buiildHeap
     * @param i the position from which to percolate down
     * @param n the binary size of the binary heap
     */
    public static void percDown(Integer[] a,int i, int n){
        int child;
        int temp;

        for(temp= a[i]; leftChild(i) < n; i = child){
            child = leftChild(i);

            if(child != n-1  && a[child] < a[child+1])
                child++;

            if(temp < a[child])
                a[i] = a[child];
            else
                break;
        }
         a[i] = temp;
    }


    private static int leftChild(int i){
        return 2 * i + 1;
    }

    public static void heapSort(Integer[] a){

        /**初始化堆的时候是对所有的非叶子结点进行筛选。
        最后一个非终端元素的下标是[n/2]向下取整,所以筛选只需要从第[n/2]向下取整个元素开始,从后往前进行调整。
         */
        for(int i = a.length/2-1; i>=0; i--){ //buildHeap
            percDown(a,i,a.length);
        }

        for(int i=a.length-1; i > 0; i--){
            swapReferences(a,0,i);  //deleteMax
            percDown(a,0,i);
        }
    }

    //deleteMax
    public static void swapReferences(Integer[] a, int i, int n){
        Integer temp=a[i];
        a[i] = a[n];
        a[n] = temp;
    }

}

  堆排序方法对记录数较少的文件并不值得提倡,但对n较大的文件还是很有效的。因为其运行时间主要耗费在建初始堆和调整建新堆时进行的反复“筛选”上

  堆排序在最坏的情况下,其时间复杂度也为O(nlogn)。相对于快速排序来说,这是堆排序的最大优点。

  

   

        

  

     

    

         

   

以上是关于学习堆排序的主要内容,如果未能解决你的问题,请参考以下文章

排序算法学习(直接插入排序,希尔排序,选择排序,堆排序,冒泡排序)

经典算法学习——堆排序

堆排序HeapSort

堆排序-学习笔记

十大经典排序算法总结(堆排序)

C# 各种内部排序方法的实现(直接插入排序希尔排序冒泡排序快速排序直接选择排序堆排序归并排序基数排序)