堆排序Heap Sort(其一)

堆排序Heap Sort

时间复杂度: O(nlogn)
在insert()操作和extractMax()操作中,时间复杂度都是logn级别的,因为shiftUp()和shiftDown()操作中,不管是将元素从下到上,从上到下一层层找到合适的位置都是和层序相关的。
二叉堆 Binary Heap:堆总是一颗完全二叉树
最大堆(大顶堆): 堆中每个节点的值总是不大于其父节点的值。
用数组存储二叉堆:
索引从1开始时,某个节点i的父节点为parent(i)=i/2,其左孩子为left child(i)=2i,其右孩子为right child(i)=2i+1.
在这里插入图片描述
大顶堆中插入元素:Shift Up
大顶堆我们通过数组来存储,向大顶堆中添加一个元素相当于向数组的末尾添加一个元素,count++。此时的堆不满足大顶堆的定义(52>16),需要进行Shift Up操作将其转化为一个大顶堆。
在这里插入图片描述
我们需要将新加入的元素调整到合适的位置,使整棵二叉树符合大顶堆的定义。具体步骤为:新加入的元素与他的父亲节点比,如果父节点比新加入的元素小,则交换两者的位置,此时52和16进行交换。
在这里插入图片描述
此时52可能还会比他此时的父亲节点大,两者进行比较,此时52>41,两者进行位置交换。
在这里插入图片描述
此时52可能还会比他此时的父亲节点大,两者进行比较,此时52<62,两者不用进行位置交换。
在这里插入图片描述
大顶堆中取出最大元素:Shift Down
在大顶堆中取出一个元素只能取出最大值。当取出堆顶元素(数组中第一个元素)时,将数组中最后一个元素移到堆顶位置,count–,此时堆依然是一课完全二叉树,但不是大顶堆,需要进行Shift Down操作将其转化为一个大顶堆。
在这里插入图片描述
将根节点元素的位置一步一步的往下移动,直到找到合适的位置。
在这里插入图片描述
左右两个孩子进行比较,谁大就和谁换。
在这里插入图片描述
继续左右两个孩子进行比较,谁大就和谁换。此时16只有左孩子,就拿他和左孩子进行比较,此时16>15,不需要进行交换,同时Shift Down也就结束了。

在这里插入图片描述

package sort.heap;
/**
 * 大顶堆
 *
 * @author cuiyongling
 * @since V1.0.0
 * 2020-04-14 12:55
 */

public class MaxHeap<E extends Comparable<E>> {
    private Object[] data;
    private int count;
    private int capacity;

    public MaxHeap(int capacity){
        data = new Object[capacity+1];
        count = 0;
        this.capacity = capacity;
    }

    public int size(){
        return count;
    }

    public boolean isEmpty(){
        return count ==0;
    }

    public void insert(E e){
        //索引从1开始
        if(count+1  <=  capacity){
            data[count+1] = e;
            count ++;
            shiftUp(count);
        }else{
            throw new IllegalArgumentException("has no space to insert a new number");
        }
    }

    private void shiftUp(int k){
        while(k > 1 && ((E)data[k/2]).compareTo((E)data[k]) <0){
            //进行位置交换 优化:每次进行比较赋值操作,而不是交换操作,就像插入排序中的优化,找到最终的位置进行插入
            E temp = (E)data[k/2];
            data[k/2]= data[k];
            data[k] = temp;

            //维护k
            k = k/2;
        }
    }

    public E extractMax(){
        if(count >0){
            E e = (E)data[1];
            E temp = (E)data[count];
            data[count] = data[1];
            data[1] = temp;

            count --;
            shiftDown(1);
            return e;
        }else{
            throw new IllegalArgumentException("has no item in array");
        }
    }

    private void shiftDown(int k){
     //当其有孩子,只要他有左孩子
        while(2*k <=count){
            //在此轮循环中,data[k]和data[j]交换位置
            int j = 2*k;
             //判断是否有右孩子
            if(j+1 <=count && ((E)data[j+1]).compareTo((E)data[j]) >0){
                j= j+1;
            }
            if(((E)data[k]).compareTo((E)data[j]) >=0){
                break;
            }
            //进行交换
            E temp = (E)data[k];
            data[k] = data[j];
            data[j] = temp;

            k = j;
        }
    }
}
package sort;
import sort.heap.MaxHeap;
/**
 * 堆排序
 *
 * @author cuiyongling
 * @since V1.0.0
 * 2020-04-14 15:55
 */

public class HeapSort<E extends Comparable<E>> {

    public void heapSort(E[] arr, int n){
        MaxHeap<E> maxHeap = new MaxHeap<>(n);
        for(int i=0; i<n;i++){
            maxHeap.insert(arr[i]);
        }
        for(int i =n-1; i>=0;i--){
            arr[i] = maxHeap.extractMax();
        }

        for(int i =0;i<n;i++){
            System.out.print(arr[i]+" ");
        }
    }

    public static void main(String[] args){
        HeapSort<Integer> heapSort = new HeapSort<>();
        int n=10;
        Integer[] arr = new Integer[n];
        Random random = new Random();
        for(int i=0; i<n;i++){
            arr[i] = random.nextInt(100);
        }
        heapSort.heapSort(arr,n);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值