堆本质或底层是一个完全二叉树,但是它跟普通的完全二叉树有所不同,完全二叉树可以用数组来存储,借助索引之间的关系来抽象构成对应的完全二叉树,当根节点索引从0开始时,索引为i的节点,其左孩子节点的索引为2i+1,右孩子为2i+2,根节点为(i-1)/2。所以说维护或建堆本质就是通过这些索引间的关系来进行不断调整。
堆分为两类:

  1. 小根堆:要求每个子树的根节点都是这颗子树中最小的
  2. 大根堆:要求每个子树的根节点都是这颗子树中最大的
    以大根堆举例:
    1、堆内维护一个int型变量size,用来表示当前堆内的元素数量
    2、维护一个T类型的数组[]data用于存储堆内元素

    一、建堆:每次插入一个数据时,都是insertInto(nums,size+1);
    然后插入后有可能破坏堆的结构,此时就需要不断向上调整
    使得每棵子树都要满足根节点最大
    二、修改:当对堆内的某个元素进行修改后,也有可能会破坏堆的结构,比如这课子树的根节点不再是最大(最小)的(如果还满足根节点最大的化则根本不需要进行调整),那么此时就需要不断向下(变小了)或者向上(变大了)进行调整,使得每个子树满足根节点最大
    三、poll():将堆顶元素(索引为0位置上存储的数)出堆,出堆后此时可以这么做,将堆顶元素与当前堆内的最后一个元素(处于size-1位置上的元素)进行交换,然后令size-1,这样原堆顶元素就位于边界之外。然后此时因为调整了堆顶有可能导致堆结构变换,此时也可能需要不断向下调整
    四、peek():堆非空的话直接return data[0];

小根堆的建堆过程及堆排序

package sort;

import java.util.Arrays;
public class MyHeapSort {
    public static int peek(int[]arr){
        if(arr == null||arr.length<=0){
            return -1;
        }
        return arr[0];
    }
    public static int pop(int[]arr){
        if(arr == null||arr.length<=0){
            return -1;
        }
        int val = arr[0];
        int size = arr.length;
        swap(arr,0,--size);
        while (size>0){
            heapfiy(arr,0,size);
            swap(arr,0,--size);
        }
        return val;
    }
    private static void swap(int[]arr,int i,int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
    private static void heapfiy(int[]arr,int idx,int size){
        int leftIdx = 2*idx+1;
        while(leftIdx<size){
            int smallestIdx = (leftIdx+1<size)?((arr[leftIdx]<=arr[leftIdx+1])?leftIdx:leftIdx+1):leftIdx;
            smallestIdx = (arr[smallestIdx]<arr[idx])?smallestIdx:idx;
            if(smallestIdx==idx){
                break;
            }
            swap(arr,idx,smallestIdx);
            idx = smallestIdx;
            leftIdx = 2*idx+1;
        }
    }
    public static void upAdj(int[]arr,int idx){//每插入一个就向上调整,使得整体符合堆的结构
        while (arr[idx] < arr[(idx - 1) / 2]) {
            swap(arr, idx, (idx - 1) / 2);
            idx = (idx - 1) / 2;
        }
    }

    public static void heapSort(int[]arr){
        if(arr == null||arr.length<2){
            return;
        }
        //这是建堆的过程,不是进行堆排序的过程
        for(int i=0;i<arr.length;i++){//模拟插入建堆向上调整,也就是每插入一个位置就向上调整
            upAdj(arr,i);
        }
        //下面这个是堆排序的过程,每次把最小值放在队尾(交换堆头和最后一个元素),然后再对堆进行堆化(向下调整),再从其内选择一个最小的放在队尾,所以堆排序得到的是个降序的有序序列
        int size = arr.length;
        swap(arr,0,--size);
        while (size>0){
            heapfiy(arr,0,size);
            swap(arr,0,--size);
        }
    }
    public static void main(String[] args) {
        int[]arr = new int[]{3,4,21,546,-12,30,23,67};
        int[]arr1 = new int[]{1,2,3,4,5,6,7};
        heapSort(arr1);
        for(int i=0;i<arr1.length;i++){
            System.out.print(arr1[i]+" ");
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值