版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/CYXLZZS/article/details/51393052
1. 概述
上文我们讲到TOP K问题最小堆的实现,采用的比较基本数据类型int。这里我们将扩展到比较对象
2. 代码实现
这里我们直接上代码,这里的扩展最小堆我们取名为ExMinHeap,实现如下
package org.cyxl.common;
/**
* 扩展最小堆,采用泛型,存储的对象必须实现Comparable接口
*
* Created by jeff on 16/5/11.
*/
public class ExMinHeap<T extends Comparable>
{
// 堆的存储结构 - 数组(这里为Object数组,数组中的具体类型为T)
private Object[] data;
/**
* 初始化堆的大小
* @param k
*/
public ExMinHeap(int k)
{
this.data = new Object[k];
}
/**
* 调整堆为最小堆, 比较时很重要的一点null为最小
*
* @param i
*/
private void adjustHeap(int i)
{
// 获取左右结点的数组下标
int l = left(i);
int r = right(i);
// 这是一个临时变量,表示 跟结点、左结点、右结点中最小的值的结点的下标
int smallest = i;
// 存在左结点,且左结点的值小于根结点的值
T parent = (T)data[i];
if (l < data.length){
T left = (T)data[l];
if(parent.compareTo(left)>0){
smallest = l;
}
}
T min = (T)data[smallest];
// 存在右结点,且右结点的值小于以上比较的较小值
if (min!=null && r < data.length){
T right = (T)data[r];
if(min.compareTo(right)>0){
smallest = r;
}
}
// 左右结点的值都大于根节点,直接return,不做任何操作
if (i == smallest)
return;
// 交换根节点和左右结点中最小的那个值,把根节点的值替换下去
swap(i, smallest);
// 由于替换后左右子树会被影响,所以要对受影响的子树再进行adjustHeap
adjustHeap(smallest);
}
/**
* 获取右结点的数组下标
* @param i
* @return
*/
private int right(int i)
{
return (i + 1) << 1;
}
/**
* 获取左结点的数组下标
*
* @param i
* @return
*/
private int left(int i)
{
return ((i + 1) << 1) - 1;
}
/**
* 交换元素位置
*
* @param i
* @param j
*/
private void swap(int i, int j)
{
T tmp = (T)data[i];
data[i] = data[j];
data[j] = tmp;
}
/**
* 替换根元素,并重新adjustHeap(注意开始根节点为null的情况)
*
* @param element
*/
public void add(T element)
{
if(element.compareTo(data[0])>0) {
//具体存储的对象类型为T
data[0] = element;
adjustHeap(0);
}
}
public String toString(){
StringBuilder builder = new StringBuilder();
builder.append("{");
for (int i=0;i<data.length;i++){
T t = (T)data[i];
if(t!=null) {
builder.append(t.toString());
if (i != data.length - 1) {
builder.append(",");
}
}
}
builder.append("}");
return builder.toString();
}
}
代码中有比较详细的注释,可以对照先前的那篇博客进行对比理解。这里我们对存入堆的对象进行泛型的控制,它必须实现Comparable接口。
3. 验证测试
首先我们先创建一个符合扩展最小堆的对象HeapData
package org.cyxl.common;
/**
* Created by jeff on 16/5/12.
*/
public class HeapData implements Comparable {
private int value;
public HeapData(int value){
this.value = value;
}
public int getValue(){
return value;
}
@Override
public int compareTo(Object o) {
if(o==null){
//这点对于比较很重要
return 1;
}
HeapData that = (HeapData)o;
if(that.getValue()==this.getValue()){
return 0;
}else if(that.getValue()>this.getValue()){
return -1;
}else {
return 1;
}
}
public String toString(){
return value+"";
}
}
由于HeapData实现了Comparable接口(必须重写compareTo方法),所以它符合扩展最小堆数据的要求
接下来我们写个main函数来测试一下
public static void main(String[] args){
int k = 10;
ExMinHeap<HeapData> exMinHeap = new ExMinHeap<HeapData>(k);
int n = 10;
for(int i=0;i<n;i++){
int value = new Random().nextInt(100);
System.out.print(value+" ");
HeapData data = new HeapData(value);
exMinHeap.add(data);
}
System.out.println();
System.out.println(exMinHeap);
}
结果为
25 58 62 99 70 11 60 62 61 78
{62,62,99,78,70}
(随机的生成的10个数字,可能数字本身和我这里有区别)