堆的基本储存和基础排序

本文详细介绍了二叉堆的概念,包括完全二叉树的定义以及二叉堆的性质。通过示例展示了如何使用shiftDown和shiftUp方法对二叉堆进行初始化和元素排序。此外,还提供了插入元素、删除元素的基本操作,并给出完整的Java代码实现。
摘要由CSDN通过智能技术生成

二叉堆可以看作是完全二叉树的数组对象,需要满足两个条件:完全二叉树;子节点不能大于父节点。

什么是完全二叉树?

二叉树的特点是每个节点的度都不能大于2,完全二叉树指的是深度为k的二叉树,除了k层以外,1--k-1层节点均达到了最大。

图1、2就是完全二叉树,图3不是

 

 

(重点)二叉堆的规律:假设当前父节点的索引为k,则它的两个子节点,左边的索引为k/2,右边为k/2+1

堆的基础代码

首先,堆内装的数据是不一定的,所以我们用使用泛型,同时因为后续需要比较,这个泛型必须要继承Comparable。其次堆的本质是一个数组,所以我们要准备一个数组来装元素,这里使用的是data[],同时我们需要一个元素来记录数组内元素的个数,这里使用多的count。

堆的初始化:

在堆的初始化前我们要先了解一个函数:shiftDown(int i)

shiftDown的作用是将i位置的元素放到正确的位置,过程为:(假设除了i位置,其他元素原本位置是正确的)首先获取子节点中元素最大的,然后与i位置的元素作比较,如果i位置的元素大,此时i位置的元素就是正确的,如果i位置的元素小,就交换i位置和子节点中最大元素的位置。依次循环,将元素放到正确位置上。

如果图所示:

此时i=2

子节点中最大元素为17,3<17交换位置

 再寻找子节点最大的元素,为6,6>3,所以交换位置

 此时完成了排序。

该函数的代码如下:

    public void shiftDown(int i){
        while (2*i <= count){
            int k = 2*i;
            if (k+1 <= count && data[k].compareTo(data[k+1]) < 0){//找出子节点最大的
                k++;
            }
            if (data[i].compareTo(data[k]) > 0){//如果子节点最大的仍然比该节点小,则完成了归位
                break;
            }
            swap(i, k);//如果最大子节点大于父节点,则交换位置
            i = k;//获取新的位置,继续比较
        }
    }

现在我们再来学习初始化:

首先要传入一个打乱的数组,我们 将这个数组进行排序,获得堆。

假设传入的数组为:{12,33,42,44,65,28,79,88,4,5,2}

当前数组情况为:

从下面开始往上做比较,第一个是11/2,也就是5位置开始使用shiftDown,65大于5所以不用换。然后4位置开始使用,因为88>44所以要交换位置,如图

 再对3位置使用,42<79,所以要交换位置:

再对2位置使用,因为33<88所以交换位置: 

因为33<44,所以继续交换位置:

最后对1使用,因为12<88,所以交换位置: 

因为12<65,继续交换:完成排序。 

代码如下:

public BasicHeapify(T[] arr) {
        int length = arr.length;
        this.capacity = length;
        count = length;
        data = (T[]) new Comparable[capacity + 1];//+1的原因是0位不装元素,从1位开始装
        for (int i = 0; i <length; i++){
            data[i+1] = arr[i];
        }
        for (int i = count / 2; i > 0 ; i--){
            shiftDown(i);//从最底部开始将元素归到正确位置,先把大的数找出,再比较
        }
    }

堆的插入:

堆的插入思路是,首先把要插入的元素放到堆的末端(要保证还有位置可以插入),然后把将该节点与父节点比较大小,如果该节点内元素大,则交换位置,如果小,则该位置是正确的。

在这之前我们同时要认识一个函数shifUp(int i)也就是上面描述的比较过程:

如现在插入一个元素42

42>28所以与之交换位置:

 

42<79,所以结束,已找到正确位置。

代码展示:

public void shiftUp(int i){
        while (i > 1 && data[i].compareTo(data[i/2]) > 0){//如果元素比父节点大,则交换位置
            swap(i, i/2);
            i /= 2;
        }
    }

 insert的代码展示:

public void insert(T t) throws Exception {
        if (count == capacity) throw new Exception("堆已满,无法再添加");
        data[count] = t;
        shiftUp(count);//将元素放到正确位置
        count ++;
    }

 整体代码展示:

package CSDN;

public class BasicHeapify<T extends Comparable> {
    private T[] data;
    private int count;
    private int capacity;

    public BasicHeapify(T[] arr) {
        int length = arr.length;
        this.capacity = length;
        count = length;
        data = (T[]) new Comparable[capacity + 1];//+1的原因是0位不装元素,从1位开始装
        for (int i = 0; i <length; i++){
            data[i+1] = arr[i];
        }
        for (int i = count / 2; i > 0 ; i--){
            shiftDown(i);//从最底部开始将元素归到正确位置,先把大的数找出,再比较
        }
    }

    public void insert(T t) throws Exception {
        if (count == capacity) throw new Exception("堆已满,无法再添加");
        data[count] = t;
        shiftUp(count);//将元素放到正确位置
        count ++;
    }

    public void shiftUp(int i){
        while (i > 1 && data[i].compareTo(data[i/2]) > 0){//如果元素比父节点大,则交换位置
            swap(i, i/2);
            i /= 2;
        }
    }

    public T extractMax(){//获取最大元素
        T t = data[1];
        swap(1,count);
        count--;
        shiftDown(1);
        return t;
    }

    public T delete(int i){//删除元素
        T t = data[i];
        swap(i,count);
        count--;
        shiftDown(i);
        return t;
    }

    public void shiftDown(int i){
        while (2*i <= count){
            int k = 2*i;
            if (k+1 <= count && data[k].compareTo(data[k+1]) < 0){//找出子节点最大的
                k++;
            }
            if (data[i].compareTo(data[k]) > 0){//如果子节点最大的仍然比该节点小,则完成了归位
                break;
            }
            swap(i, k);//如果最大子节点大于父节点,则交换位置
            i = k;//获取新的位置,继续比较
        }
    }

    public void swap(int i, int j){//交换位置的函数
        T a = data[i];
        data[i] = data[j];
        data[j] = a;
    }
    public int getSize(){//获得大小
        return count;
    }

    public boolean isEmpty(){//判断是否为空
        return count == 0;
    }

    public static void main(String[] args) {
        Integer[] a = {12,32,44,54,234,432,66,44,94,23};
        BasicHeapify<Integer> heapify = new BasicHeapify<Integer>(a);
        for (int i = 1; i < heapify.capacity+1; i++) {
            System.out.println(heapify.extractMax());
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lxiaowangtongxue

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值