数据结构与算法

【数据结构与算法】堆排序算法回顾

2019-04-25  本文已影响335人  叫我不矜持

一.堆排序介绍

堆排序是利用堆这种数据结构而设计的一种排序算法,堆排序是一种选择排序,它的最坏,最好,平均时间复杂度均为O(nlogn),它也是不稳定排序。

堆排序的应用场景主要有:topk问题,优先级队列等。

原理:
1.将存放在array[0,…,n-1]中的n个元素建成初始堆;
2.此时,堆顶元素该堆的最大值
3.将堆顶元素与堆底元素进行交换,则序列的最大值即已放到正确的位置;
4.但此时堆被破坏,将堆顶元素向下调整使其继续保持大根堆的性质,再重复第3,4步,直到堆中仅剩下一个元素为止。

堆排序

二.堆排序的代码示例

1.初始化堆

public static void initHeap(){
        heap = new int[]{1,2,3,4,5,6,7,8,9,10};
        //heap.length/2-1确定最后一个有子节点的节点
        for(int i = heap.length/2-1;i>=0;i--){
            adjustHeap(i);
        }


    }

    public static void adjustHeap(int i){
        //确定该节点的左子节点和右子节点
        int right = i*2+2;
        int left = i*2+1;
        int max = i;

        if(heap[i]<heap[left]){
            max = left;
        }
        if(right<heap.length&&heap[max]<heap[right]){
            max = right;
        }
        if(max!=i){
            swap(max,i);

            adjustHeap(i);
        }
    }

    public static void swap(int x,int y){
        int temp = heap[x];
        heap[x]=heap[y];
        heap[y]=temp;
    }

经过初始化堆的过程,现在可以发现,最大的数已经在堆顶了
2.堆排序
现在我们要做的是将整个堆变成有序的堆

public static void initHeap(){
        heap = new int[]{1,2,3,4,5,6,7,8,9,10};
        //heap.length/2-1确定最后一个有子节点的节点
        for(int i = heap.length/2-1;i>=0;i--){
            adjustHeap(i,heap.length);
        }
        //堆排序
        for (int i = heap.length-1; i >0 ; i--) {
            //每次讲最大值放到最后
            swap(i, 0);
            //注意这里传入的是i,排除了最后已排序的元素,例如:最后一个元素是我们交换过去的,是最大的,不参与排序
            adjustHeap(0,i);

        }

    }

    public static void adjustHeap(int i,int length){
        //确定该节点的左子节点和右子节点
        int right = i*2+2;
        int left = i*2+1;
        int max = i;
        System.out.println(right+":"+left+":"+length);
        //判断最大值
        if(left<length&&heap[i]<heap[left]){
            max = left;
        }
        if(right<length&&heap[max]<heap[right]){
            max = right;
        }
        if(max!=i){
            //交换
            swap(max,i);
            //递归排序
            adjustHeap(max,length);
        }
    }

    public static void swap(int x,int y){
        int temp = heap[x];
        heap[x]=heap[y];
        heap[y]=temp;
    }

三.总结

堆排序是一种选择排序,整体主要由构建初始堆+交换堆顶元素和末尾元素并重建堆两部分组成。其中构建初始堆经推导复杂度为O(n),在交换并重建堆的过程中,需交换n-1次,而重建堆的过程中,根据完全二叉树的性质,[log2(n-1),log2(n-2)...1]逐步递减,近似为nlogn。所以堆排序时间复杂度一般认为就是O(nlogn)级。

四.非递归方式实现堆排序

 public static void adjustHeap(int i,int length){
        int max = i;
        int right = i*2+2;
        int left = i*2+1;
        while(left<length){

            //判断最大值
            if(left<length&&heap[i]<heap[left]){
                max = left;
            }
            if(right<length&&heap[max]<heap[right]){
                max = right;
            }
            if(max==i){
                break;
            }
            //交换
            swap(max,i);
            i=max;
            //确定该节点的左子节点和右子节点
            right = i*2+2;
            left = i*2+1;
        }
    }
上一篇 下一篇

猜你喜欢

热点阅读