首页 > 代码库 > 算法三之堆排序

算法三之堆排序

一、堆(Heap)定义

(1)n个关键字序列Kl,K2,…,Kn称为(Heap),当且仅当该序列满足如下性质(简称为堆性质):

       k(i)<=k(2i)且k(i)<=k(2i+1)(1≤i≤ n/2),

       当然,这是小根堆,大根堆则换成>=号。

(2)k(i)相当于二叉树的非叶子结点,K(2i)则是左子节点,k(2i+1)是右子节点

       若将此序列所存储的向量R[1..n]看做是一棵完全二叉树的存储结构,则堆实质上是满足如下性质的完全二叉树:
树中任一非叶子结点的关键字均不大于(或不小于)其左右孩子(若存在)结点的关键字。

 

二、堆排序的思想

      堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。
(1)用大根堆排序的基本思想
① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区
② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key
③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。
……
直到无序区只有一个元素为止。

 

三、算法实现

    /**
     * 堆排序
     * @param data  数据队列
     */
    public static void heapSort(int[] data) {
        //初始化大堆
        for (int i = data.length / 2 - 1; i >= 0; i--) {
            adjustHeap(data, i, data.length);  //指定父节点堆调整
        }

        int temp;    //临时空间
        for (int i = data.length - 1; i > 0; i--) {
            //堆首与堆尾交换
            temp = data[i];
            data[i] = data[0];
            data[0] = temp;
            //大堆调整
            adjustHeap(data, 0, i);
        }

    }
    /**
     * 堆调整
     * @param data  数据队列
     * @param start  起始位置
     * @param end   截止位置,是堆尾的下一个位置
     */
    public static void adjustHeap(int[] data, int start, int end) {
        
        int src=http://www.mamicode.com/data[start];  //保存起始位置的值
        for (int i = start * 2 + 1; i < end; i *= 2 + 1) {
            //判断左右节点大小
            if (i < end - 1 && data[i] < data[i + 1]) {
                i++;  //右节点大
            }
            //起始位置值最大
            if(data[start]>data[i])
                break;
            
            data[start]=data[i];//赋值最大值
            start=i; //记录大值的位置
        }
        data[start]=src;//回填大值位置
    }

 

四、算法复杂度

     堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,它们均是通过调用adjustHeap实现的。

     平均性能O(N*logN),由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。

     堆排序是就地排序,辅助空间为O(1).
    它是不稳定的排序方法。(排序的稳定性是指如果在排序的序列中,存在前后相同的两个元素的话,排序前 和排序后他们的相对位置不发生变化)

 

算法三之堆排序