二叉树(堆和优先队列)

堆是一种特殊的二叉树。

最小值堆:最小值堆的特性。

对于堆的任意非叶节点K,K的值总是小于或者等于左右子节点。

K <= 左节点;K <= 又节点;

堆实例:

堆实际上是一个完全二叉树(若设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树。)可以用数组表示。

堆中存储是局部有序的。

创建堆:

交换创建堆,交换有2,1)向下交换,2)向上交换。

1)向下交换。

假设根的左右子树都已是堆,并且根元素为R,此时有2种情况。

  (1)R的值小于或者等于左右子结点,此时堆完成。

  (2)R的值大于其中一个或者两个子女,此时R应该与两个子女中较小的一个交换,结果得到一个新堆,

R到达新位置后继续和其两个子女,如果R小于或者等于其左右子女,建堆完成,否则重复上一过程,直到

R小于或等于其左右子女,或R成为新的叶结点。

 

堆的数组实现:

public abstract class AbstractHeap<T extends Comparable<T>> implements Heap<T>  {

    //最大堆大小
    private static final int MAX_SIZE = Integer.MAX_VALUE;

    //数组大小
    protected int size;
    //堆中数组个数
    protected int currentSize;
    //存储堆的数据
    protected T[] data;

    AbstractHeap(){
        this(0,16,null);
    }

    AbstractHeap(T[] data){
        this(data.length,data.length,data);
    }

    AbstractHeap(int currentSize,int size,T[] data){
        this.currentSize = currentSize;
        this.size = size;
        this.data = data;
        if (data != null)
//根据给定数组 创建堆
            buildHeap(data);
    }
}

用给定的数组创建堆,从堆中第一个分支结点,从下往上网上交换创建堆:

    private void buildHeap(T[] t){
        if (t.length > 1){
            //从下到上第一个分支结点
            int pos = t.length / 2 - 1;
            for (int i = pos ; i >= 0 ; i -- ){
//向下交换
                siftDown(i);
            }
        }
    }

交换函数:

void siftDown(int pos) {
// pos为第一个分支结点位置
        int tmp = pos;
// j为其左结点
        int j = tmp * 2 + 1;
//保存当前结点值
        T tmpNode = data[tmp];
        while ( j < currentSize){
//j < currentSize - 1 防止右结点不存在,j+1 = tmp *2 +1 ,data[j+1] 为右结点

            if (j < currentSize - 1 && data[j].compareTo(data[j+1]) == 1){
//若右结点值比较小,j++
                j++;
            }
            if (tmpNode.compareTo(data[j]) == 1){
//若当前结点值大于左右结点中最小的值,将最小的哪个结点值上移当前结点,
                data[tmp] = data[j];
//tmp 为上移结点下标
                tmp = j;
                j = j * 2 + 1;
            }
//如果当前结点值小于其左右子女中最小的,建堆完成,跳出循环
else break;
//将当前结点值 赋值给上移结点
            data[tmp] = tmpNode;
        }
    }

2)向上交换

在堆中新增值时,采用向上交换:

    public boolean insert(T t) {
        if (t == null){
            return false;
        }
        if (currentSize == size){
            return false;
        }
//直接将新增值放到数组的最后一个位置,并向上交换
        data[currentSize] = t;
        siftUp(currentSize);
        currentSize ++;
        return true;
    }
    void siftUp(int pos) {
//当前位置下标
        int tmp = pos;
//父结点下标
        int j = (pos - 1) / 2;
//当前结点
        T tmpNode = data[tmp];
        while (j >= 0){
//如果当前结点值小于父结点,当前结点值向上移动,直到根结点或者当前结点值打于根结点值跳出循环
            if (tmpNode.compareTo(data[j]) == -1){
                data[tmp] = data[j];
                tmp = j;
                j = j / 2 - 1;
            }else break;
            tmpNode = data[tmp];
        }
    }

创建堆可以根据已有数据创建采用向下移动创建,也可以一个一个的插入值,采用向上移动的方法创建堆。

小结:

堆的特性,父结点的值小于左右子女结点值。

堆保持局部有序性,可以用左优先队列。

堆排序时间复杂度为O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值