• 算法三之堆排序


    一、堆(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=data[start];  //保存起始位置的值
            for (int i = start * 2 + 1; i < end; i = i * 2 + 1) {
                //判断左右节点大小
                if (i + 1 < end && data[i] < data[i + 1]) {
                    i++;  //右节点大
                }
                //起始位置值最大
                if(src >= data[i])
                    break;
                
                data[start]=data[i];//赋值最大值
                start=i; //记录大值的位置
            }
            data[start]=src;//回填起始值
        }

    四、算法复杂度

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

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

         堆排序是就地排序,辅助空间为O(1).
        它是不稳定的排序方法。(排序的稳定性是指如果在排序的序列中,存在前后相同的两个元素的话,排序前 和排序后他们的相对位置不发生变化)
  • 相关阅读:
    poj 1010
    poj 1060
    poj 1001
    POJ 2769
    POJ 2559
    poj 2403
    POJ 1088
    设置全屏与退出全屏
    iframe 父子页面方法调用
    Web 前端面试小知识
  • 原文地址:https://www.cnblogs.com/maokun/p/7078073.html
Copyright © 2020-2023  润新知