堆排序

2020-01-17  本文已影响0人  吕建雄

堆:是具有下列特性的完全二叉树;每个节点的值都大于或等于其左右孩子节点的值,称为大顶堆;或者每个节点的值都小于或等于其左右孩子节点的值,称为小顶堆

堆排序:(两个问题)

1、如何由一个无序序列构建成一个堆

2、如何在输出堆顶元素后,调整剩余元素成为一个新的堆

    将待排序的序列构建成一个大顶堆,其实就是从下往上、从右到左,将每个非终点节点当作根节点,将其和其子树调整成大顶堆

    将待排序的序列构造成一个大顶堆。此时整个序列的最大值就是堆顶的根节点。将它移走(其实就是将其与堆数组的末尾元素进行交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成一个堆,这样就会得到n个元素中的次大值;如此反复,就能得到一个有序序列啦

class HeapSort {

    public static void main(String[] argv){

        int[] arr = {50,10,90,40,60,80,70,30,20};

        System.out.println("排序前...");

          for(int i=0;i<arr.length;i++){

            System.out.println(arr[i]);

        }

        System.out.println("排序后...");

        heapSort(arr);

        for(int i=0;i<arr.length;i++){

            System.out.println(arr[i]);

        }

    }

    //堆构造

    public static void heapBuilder(int[] arr, int s, int length){

        int k = s;

        int guard = arr[s];//哨兵对象

        //此处为什么index = 2*k+1完全二叉树的特性决定,第i个节点其左子节点为2i,右子节点为2i+1

        //而数组的索引从0开始,所以此处需要+1

        int index = 2*k +1;

        while(index<length){

            if(index+1 < length){

                if(arr[index]<arr[index+1]){

                    index++;

                }

            }

            if(arr[index] > guard){

                arr[k] = arr[index];

                k = index;

                index = 2*k +1;

            } else {

                break;

            }

        }

        arr[k] = guard;

    }

    public static void heapSort(int[] arr){

        //堆构造,从第一个非子叶节点开始(arr.length/2-1)

        for(int i=arr.length/2-1;i>=0;i--){

            heapBuilder(arr,i,arr.length);

        }

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

            //通过交换,将最大值放入到堆的末尾

            int max = arr[0];

            arr[0] = arr[i];

            arr[i] = max;

            heapBuilder(arr,0,i);

        }

    }

}

代码实现

运行时间完全消耗在初始构建堆和重建堆时的反复筛选上

在构建堆的过程中,因为是完全二叉树从最下层最右边的非终点节点开始构建,将它与其孩子进行比较和有必要的交换,对于每个非终节点来说,最多两次比较和互换操作,因为整个构建堆的时间复杂度为O(n)

正式排序时,第i此取堆顶记录重建堆需要用O(logi)的时间(完全二叉树的每个节点到根节点的距离为log(2)i+1),并且需要取n-1次堆顶记录,因此重建堆的时间复杂度为O(nlogn)

总体来说,堆排序的时间复杂度为O(nlogn)

上一篇 下一篇

猜你喜欢

热点阅读