大堆和小堆的实现

142 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

堆只有大根堆和小根堆,而且他们都是完全二叉树

大根堆就是大的在上面

小根堆就是小的在上面

我们用数组实现堆(链表实现也是可以的)

大根堆的实现

public static class MyBigHeap{
    private int[]heap;
    private int size;
    public MyBigHeap(int length){
        heap = new int[length];
        size = 0;
    }
}

我们先创建我们的大根堆的类,我们在这里是数组实现的,读者要是想链表实现也不是不可以。

里面的size属性是控制堆内元素多少的。

那我们看看里面的方法

push方法

public void push(int val){
    if(size == heap.length){
        System.out.println("堆满了");
        return;
    }
    heap[size] = val;
    heapInsert(heap , size++);
}
private void heapInsert(int[] heap , int index){
    while(heap[index] > heap[(index - 1)/2]){
        swap(heap , index , (index - 1)/2);
        index = (index - 1)/2;
    }
}
private void swap(int[] heap , int i , int j){
    int t = heap[i];
    heap[i] = heap[j];
    heap[j] = t;
}

上三个方法就是实现了一个压入的方法。 我们从简单的开始说

第三个方法就是简单的一个交换方法,交换数组里面的内容

第一个方法就是一个调用方法,也不是核心

第二个方法就是核心了。

我们先介绍一下参数,第一个参数是数组实现的堆 ,第二个参数就是push的位置,

(index - 1)/2 这个操作其实是找到index元素的父母。

如果自己的元素比父母大,那么就交换元素

pop方法

private void heapFy(int[] heap , int index){
    int child = index * 2 + 1;
    while(child < size){
        if(child < size - 1 && heap[child] < heap[child + 1]){
            child++;
        }
        if(heap[index] < heap[child]){
            swap(heap , index , child);
            index = child;
            child = index * 2 + 1;
        }else{
            break;
        }
    }
}

public int pop(){
    if(size == 0){
        System.out.println("堆为空");
        return -1;
    }
    int ret = heap[0];
    swap(heap , 0 , --size);
    heapFy(heap , 0);
    return ret;
}

我们还是按照上面的讲解,我们先讲解最简单的,第二个函数就是一个调用函数,值得注意的是用尾巴元素去交换头元素。

这个做法可以让整个堆重新排列,并且可以做到隐形删除。其实我们知道交换之后,元素并没有被删除,只是放到了最后,然后size--

第一个方法就是让最上面的元素排到应该在的地方。

child表示的是index位置的孩子,然后在不超过允许范围内,比较两个孩子的大小,让大的孩子替代自己。

小根堆的实现

小根堆的实现其实和大根堆是一样的,只是大小位置换一下,这边就不做过多的介绍了。