堆(二)优先队列

优先队列

使用最大堆或者最小堆来实现一个优先队列是非常合适的。这个优先队列需要实现插入新值、改变键值和抽取最大/最小元素的功能。实现如下:

package heap;

public class PriorityQueue <T extends Heap> {
    private T heap;
    public PriorityQueue(T heap) {
        this.heap = heap;
    }

    public int extract() {
        return heap.extract();
    }

    public void insert(int key) {
        heap.insert(key);
    }

    public void changeKey(int i, int key) {
        heap.changeKey(i, key);
    }

    @Override
    public String toString() {
        return heap.toLineStr();
    }
}

这里我使用了泛型类,虽然不是非常有必要。采用的设计模式是策略模式,策略就是Heap, 可能是最大堆或者最小堆。它主要有下面三个接口:

1. extract: 抽取最大或者最小元素,并保证原有堆的性质不变。

2. insert: 插入新的键值。

3. changeKey: 对于最大堆来说,是增大键值。对于最小堆来说,是减小键值。

extract

它定义在Heap里面,实现起来很简单,就是抽取items[0],并将items的最后一个元素换到前面来,并调用heapify方法,保持堆的性质不变。代码如下:

public abstract class Heap {
    // 取出最大元素,并恢复其为最大堆或者最小堆
    public int extract() {
        if (heapSize < 1) throw new RuntimeException("heap underflow.");
        int tmp = items[0];
        items[0] = items[--heapSize];
        heapify(0);
        return tmp;
    }
}

changeKey

public abstract class Heap {
    // 将第i个元素的值改掉
    public abstract void changeKey(int i, int key);
}

这个方法,对于最大堆来说,是increaseKey;对于最小堆来说,是decreaseKey方法。实现思路是,将当前元素与父元素比较,如果不满足堆性质,将它们进行调换,并继续往父元素比较。这个方法其实是有问题的,因为无法获得i的值,所以具体使用的时候,要么对items进行改进,增加对应下标i的属性;要么在堆中建立从key到i的映射关系。

public class MaxHeap extends Heap {
    // increase key
    @Override
    public void changeKey(int i , int key) {
        if (i >= heapSize) throw new RuntimeException("invalid index");
        // 必须是增大的
        if (key < items[i]) throw new RuntimeException("key smaller than original value");
        items[i] = key;
        // i > 0 等价于 parent(i)>-1;
        while(i > 0 && items[parent(i)] < items[i]) {
            int tmp = items[parent(i)];
            items[parent(i)] = items[i];
            items[i] = tmp;
            i = parent(i);
        }
    }
}

public class MinHeap extends Heap{
    @Override
    public void changeKey(int i, int key) {
        if (i >= heapSize) throw new RuntimeException("invalid index");
        if (key > items[i]) throw new RuntimeException("key larger than original value");
        items[i] = key;
        while(i > 0 && items[parent(i)] > items[i]) {
            int tmp = items[parent(i)];
            items[parent(i)] = items[i];
            items[i] = tmp;
            i = parent(i);
        }
    }
}

insert

public abstract class Heap {
    // 插入元素
    public abstract void insert(int key);
}

插入新值。实现思路:在heap末尾新增一个值,再调用changeKey方法。

public class MaxHeap extends Heap {
    // negative infinity;
    @Override
    public void insert(int key) {
        if (heapSize+1 > items.length) throw new RuntimeException("overflow");
        heapSize++;
        items[heapSize-1] = Integer.MIN_VALUE;
        changeKey(heapSize-1, key);
    }
}

public class MinHeap extends Heap{
    // positive infinity
    @Override
    public void insert(int key) {
        if (heapSize+1 > items.length) throw new RuntimeException("heap overflow");
        heapSize++;
        items[heapSize-1] = Integer.MAX_VALUE;
        changeKey(heapSize-1, key);
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值