Java 堆接口和实现

Posted liujinming

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 堆接口和实现相关的知识,希望对你有一定的参考价值。

我今天在处理topk问题的时候需要一个堆容器,翻了半天资料没找到,最后偶然看到了这张图:

技术分享图片

啧啧啧,这张图上居然没有堆(heap)。

好像java中真的没有听说过堆这么个容器……

只好自己动手丰衣足食了

接口:

/**
 * 
 */
package com.lille.tool.heap;

import java.util.Collection;
import java.util.NoSuchElementException;

/**
 * 
 * @author Lille [email protected]
 * @time 2018年4月1日 下午7:31:07
 */
public interface Heap<T extends Comparable<T>> extends Collection<T> {
    int size();

    /**
     * 取得但并不删除堆顶元素,返回null,如果这个堆是空的 <br/>
     * Retrieves, but does not remove, the head of this Heap, or returns
     * {@code null} if this Heap is empty.
     * 
     * @return 堆顶元素<br/>
     *         the head of this heap, or {@code null} if this heap is empty
     *
     */
    T peek();

    /**
     * 取得但不删除堆顶元素,这个方法和peek的唯一区别是当堆为空时抛出一个NoSuchElementException <br/>
     * Retrieves, but does not remove, the top of this Heap. This method differs
     * from {@link #peek peek} only in that it throws an exception if this Heap
     * is empty.
     * 
     * @return 堆顶元素<br/>
     *         the top of this Heap
     * @throws NoSuchElementException
     *             当且仅当堆是空的 <br/>
     *             if this Heap is empty
     */
    T element();

    /**
     * 返回并删除堆顶元素,该方法和poll方法唯一的不同是当堆为空时抛出异常
     * 
     * <br/>
     * Retrieves and removes the top of this heap. This method differs from
     * {@link #poll poll} only in that it throws an exception if this heap is
     * empty.
     * 
     * @return 堆顶元素<br/>
     *         the top of this heap
     * @throws NoSuchElementException
     *             当且仅当堆为空时 <br/>
     *             if this heap is empty
     */
    T remove();

    /**
     * 返回并删除堆顶元素<br/>
     * Retrieves and removes the top of the heap, or returns {@code null} if
     * this heap is empty.
     *
     * @return 堆顶元素<br/>
     *         the top of the heap, or {@code null} if this heap is empty
     */
    T poll();

    /**
     * 插入特定元素到这个堆中,该方法不同于{@link #add add}的地方在于堆满时返回false,而不抛出异常 <br/>
     * Inserts the specified element into this heap if it is possible to do so
     * immediately without violating capacity restrictions.The method differs
     * from {@link #add add} only in that it return false when there are no
     * place to insert the element but not throw a exception.
     * 
     * @param t
     *            需要插入的元素<br/>
     *            the specified element
     * @return 插入成功则返回true,否则返回false<br/>
     *         {@code true} if the element was insert to this heap, else
     *         {@code false}
     */
    boolean insert(T t);
    
    boolean add(T t);

}

实现:

最大堆:

/**
 * 
 */
package com.lille.tool.heap;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * 最大堆
 * 
 * @author Lille [email protected]
 * @time 2018年4月1日 下午7:31:07
 */
public class MaxHeapImpl<T extends Comparable<T>> implements Heap<T> {
    private ArrayList<T> heap;

    public MaxHeapImpl() {
        heap=new ArrayList<T>();
    }

    public MaxHeapImpl(Collection<? extends T> c) {
        heap=new ArrayList<T>(c.size()+1);
        for (T t : c)
            insert(t);
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#isEmpty()
     */
    @Override
    public boolean isEmpty() {
        // TODO 自动生成的方法存根
        return heap.isEmpty();
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#contains(java.lang.Object)
     */
    @Override
    public boolean contains(Object o) {
        // TODO 自动生成的方法存根
        return heap.contains(o);
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#iterator()
     */
    @Override
    public Iterator<T> iterator() {
        // TODO 自动生成的方法存根
        return new Itr();
    }

    private class Itr implements Iterator<T> {
        int cursor = 0; // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        /*
         * (非 Javadoc)
         * 
         * @see java.util.Iterator#hasNext()
         */

        @Override
        public boolean hasNext() {
            // TODO 自动生成的方法存根
            return cursor < heap.size();
        }

        /*
         * (非 Javadoc)
         * 
         * @see java.util.Iterator#next()
         */
        @Override
        public T next() {
            // TODO 自动生成的方法存根
            lastRet = cursor;
            return heap.get(cursor++);
        }

        @Override
        public void remove() {
            if(lastRet<0)throw new RuntimeException("lastRet"+lastRet);
            MaxHeapImpl.this.remove(lastRet);
            lastRet=-1;
            cursor--;
        }
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#toArray()
     */
    @Override
    public Object[] toArray() {
        // TODO 自动生成的方法存根
        return heap.toArray();
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#toArray(java.lang.Object[])
     */

    @Override
    public <E> E[] toArray(E[] a) {
        // TODO 自动生成的方法存根
        return heap.toArray(a);
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#remove(java.lang.Object)
     */
    @Override
    public boolean remove(Object o) {
        // TODO 自动生成的方法存根
        int flag = heap.size();
        for (int i = 0; i < heap.size(); i++) {
            if (heap.get(i).equals(o)) {
                remove(i);
                i--;
            }
        }
        return flag > heap.size();
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#containsAll(java.util.Collection)
     */
    @Override
    public boolean containsAll(Collection<?> c) {
        // TODO 自动生成的方法存根
        return heap.containsAll(c);
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#addAll(java.util.Collection)
     */
    @Override
    public boolean addAll(Collection<? extends T> c) {
        // TODO 自动生成的方法存根
        for (T t : c) {
            insert(t);
        }
        return true;
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#removeAll(java.util.Collection)
     */
    @Override
    public boolean removeAll(Collection<?> c) {
        // TODO 自动生成的方法存根
        int flag = heap.size();
        for (Object t : c)
            remove(t);
        return flag > heap.size();
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#retainAll(java.util.Collection)
     */
    @Override
    public boolean retainAll(Collection<?> c) {
        // TODO 自动生成的方法存根
        int flag = heap.size();
        for (int i = 0; i < heap.size(); i++) {
            if (!c.contains(heap.get(i))) {
                remove(heap.get(i));
                i--;
            }
        }
        return flag > heap.size();
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#clear()
     */
    @Override
    public void clear() {
        // TODO 自动生成的方法存根
        heap.clear();
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#size()
     */
    @Override
    public int size() {
        // TODO 自动生成的方法存根
        return heap.size();
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#peek()
     */
    @Override
    public T peek() {
        // TODO 自动生成的方法存根
        return heap.isEmpty() ? null : heap.get(0);
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#element()
     */
    @Override
    public T element() {
        // TODO 自动生成的方法存根
        if (heap.isEmpty())
            throw new NoSuchElementException();
        return heap.get(0);
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#remove()
     */
    @Override
    public T remove() {
        if (heap.isEmpty())
            throw new NoSuchElementException();
        // TODO 自动生成的方法存根
        return remove(0);
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#poll()
     */
    @Override
    public T poll() {
        // TODO 自动生成的方法存根
        if (heap.isEmpty())
            return null;
        return remove(0);
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#insert(java.lang.Comparable)
     */
    @Override
    public boolean insert(T t) {
        // TODO 自动生成的方法存根
        heap.add(t);
        Up(heap.size()-1);
        return true;
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#add(java.lang.Comparable)
     */
    @Override
    public boolean add(T t) {
        // TODO 自动生成的方法存根
        return insert(t);
    }

    /**
     * 删除
     * 
     * @param index
     * @return
     */
    protected T remove(int index) {
        T t = heap.get(index);
        heap.set(index, heap.get(heap.size()-1));
        heap.remove(heap.size()-1);
        Down(index);
        return t;
    }

    /**
     * 上浮
     * 
     * @param index
     */
    private void Up(int index) {
        while (index > 0) {
            int parent = index / 2;
            if (heap.get(parent).compareTo(heap.get(index)) >= 0)
                break;
            swap(index, parent);
            index = parent;
        }
    }

    /**
     * 下沉
     * 
     * @param index
     */
    private void Down(int index) {
        while (2 * index <= this.size() - 1) {
            int child = 2 * index;
            if (child < this.size() - 1 && heap.get(child).compareTo(heap.get(child + 1)) < 0) {
                child++;
            }
            if (heap.get(index).compareTo(heap.get(child)) >= 0) {
                break;
            }
            swap(index, child);
            index = child;
        }
    }

    private void swap(int a, int b) {
        T temp = heap.get(a);
        heap.set(a, heap.get(b));
        heap.set(b, temp);
    }
    public String toString(){
        return heap.toString();
    }
    public int hashCode(){
        return heap.hashCode();
    }
    @SuppressWarnings("rawtypes")
    public boolean equals(Object object){
        if(object==this)return true;
        if(object==null) return false;
        if(this.getClass()!=object.getClass())
            return false;
        return heap.equals(((MaxHeapImpl)object).heap);
        
    }
}

最小堆:

/**
 * 
 */
package com.lille.tool.heap;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;

/**
 * 最小堆
 * @author Lille [email protected]
 * @time 2018年4月1日 下午11:50:03
 */
public class MinHeapImpl<T extends Comparable<T>> implements Heap<T> {
    private ArrayList<T> heap;

    public MinHeapImpl() {
        heap=new ArrayList<T>();
    }

    public MinHeapImpl(Collection<? extends T> c) {
        heap=new ArrayList<T>(c.size()+1);
        for (T t : c)
            insert(t);
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#isEmpty()
     */
    @Override
    public boolean isEmpty() {
        // TODO 自动生成的方法存根
        return heap.isEmpty();
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#contains(java.lang.Object)
     */
    @Override
    public boolean contains(Object o) {
        // TODO 自动生成的方法存根
        return heap.contains(o);
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#iterator()
     */
    @Override
    public Iterator<T> iterator() {
        // TODO 自动生成的方法存根
        return new Itr();
    }

    private class Itr implements Iterator<T> {
        int cursor = 0; // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        /*
         * (非 Javadoc)
         * 
         * @see java.util.Iterator#hasNext()
         */

        @Override
        public boolean hasNext() {
            // TODO 自动生成的方法存根
            return cursor < heap.size();
        }

        /*
         * (非 Javadoc)
         * 
         * @see java.util.Iterator#next()
         */
        @Override
        public T next() {
            // TODO 自动生成的方法存根
            lastRet = cursor;
            return heap.get(cursor++);
        }

        @Override
        public void remove() {
            if(lastRet<0)throw new RuntimeException("lastRet"+lastRet);
            MinHeapImpl.this.remove(lastRet);
            lastRet=-1;
            cursor--;
        }
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#toArray()
     */
    @Override
    public Object[] toArray() {
        // TODO 自动生成的方法存根
        return heap.toArray();
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#toArray(java.lang.Object[])
     */

    @Override
    public <E> E[] toArray(E[] a) {
        // TODO 自动生成的方法存根
        return heap.toArray(a);
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#remove(java.lang.Object)
     */
    @Override
    public boolean remove(Object o) {
        // TODO 自动生成的方法存根
        int flag = heap.size();
        for (int i = 0; i < heap.size(); i++) {
            if (heap.get(i).equals(o)) {
                remove(i);
                i--;
            }
        }
        return flag > heap.size();
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#containsAll(java.util.Collection)
     */
    @Override
    public boolean containsAll(Collection<?> c) {
        // TODO 自动生成的方法存根
        return heap.containsAll(c);
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#addAll(java.util.Collection)
     */
    @Override
    public boolean addAll(Collection<? extends T> c) {
        // TODO 自动生成的方法存根
        for (T t : c) {
            insert(t);
        }
        return true;
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#removeAll(java.util.Collection)
     */
    @Override
    public boolean removeAll(Collection<?> c) {
        // TODO 自动生成的方法存根
        int flag = heap.size();
        for (Object t : c)
            remove(t);
        return flag > heap.size();
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#retainAll(java.util.Collection)
     */
    @Override
    public boolean retainAll(Collection<?> c) {
        // TODO 自动生成的方法存根
        int flag = heap.size();
        for (int i = 0; i < heap.size(); i++) {
            if (!c.contains(heap.get(i))) {
                remove(heap.get(i));
                i--;
            }
        }
        return flag > heap.size();
    }

    /*
     * (非 Javadoc)
     * 
     * @see java.util.Collection#clear()
     */
    @Override
    public void clear() {
        // TODO 自动生成的方法存根
        heap.clear();
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#size()
     */
    @Override
    public int size() {
        // TODO 自动生成的方法存根
        return heap.size();
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#peek()
     */
    @Override
    public T peek() {
        // TODO 自动生成的方法存根
        return heap.isEmpty() ? null : heap.get(0);
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#element()
     */
    @Override
    public T element() {
        // TODO 自动生成的方法存根
        if (heap.isEmpty())
            throw new NoSuchElementException();
        return heap.get(0);
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#remove()
     */
    @Override
    public T remove() {
        if (heap.isEmpty())
            throw new NoSuchElementException();
        // TODO 自动生成的方法存根
        return remove(0);
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#poll()
     */
    @Override
    public T poll() {
        // TODO 自动生成的方法存根
        if (heap.isEmpty())
            return null;
        return remove(0);
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#insert(java.lang.Comparable)
     */
    @Override
    public boolean insert(T t) {
        // TODO 自动生成的方法存根
        heap.add(t);
        Up(heap.size()-1);
        return true;
    }

    /*
     * (非 Javadoc)
     * 
     * @see com.lille.tool.heap.MaxHeap#add(java.lang.Comparable)
     */
    @Override
    public boolean add(T t) {
        // TODO 自动生成的方法存根
        return insert(t);
    }

    /**
     * 删除
     * 
     * @param index
     * @return
     */
    protected T remove(int index) {
        T t = heap.get(index);
        heap.set(index, heap.get(heap.size()-1));
        heap.remove(heap.size()-1);
        Down(index);
        return t;
    }

    /**
     * 上浮
     * 
     * @param index
     */
    private void Up(int index) {
        while (index > 0) {
            int parent = index / 2;
            if (heap.get(parent).compareTo(heap.get(index)) <= 0)
                break;
            swap(index, parent);
            index = parent;
        }
    }

    /**
     * 下沉
     * 
     * @param index
     */
    private void Down(int index) {
        while (2 * index <= this.size() - 1) {
            int child = 2 * index;
            if (child < this.size() - 1 && heap.get(child).compareTo(heap.get(child + 1)) > 0) {
                child++;
            }
            if (heap.get(index).compareTo(heap.get(child)) <= 0) {
                break;
            }
            swap(index, child);
            index = child;
        }
    }

    private void swap(int a, int b) {
        T temp = heap.get(a);
        heap.set(a, heap.get(b));
        heap.set(b, temp);
    }
    public String toString(){
        return heap.toString();
    }
    public int hashCode(){
        return heap.hashCode();
    }
    @SuppressWarnings("rawtypes")
    public boolean equals(Object object){
        if(object==this)return true;
        if(object==null) return false;
        if(this.getClass()!=object.getClass())
            return false;
        return heap.equals(((MinHeapImpl)object).heap);
        
    }
}

其实最大堆和最小堆的区别只是改了下沉和上浮里面的两个大于小于号,其它地方(包括注释)都是直接拷贝的。

测试用例:

 1     @Test
 2     public void test() {
 3         Heap<Double> heap = new MinHeapImpl<Double>();
 4         double[] f = new double[] { 1.3, 3.4, 5.7, 5.4, 8.5, 9.3, 3.0, 4.4 };
 5         for (double d : f)
 6             heap.insert(d);
 7         System.out.println(heap);
 8         Iterator<Double> it = heap.iterator();
 9         while (it.hasNext()) {
10             if (it.next() < 5) {
11                 it.remove();
12                 System.out.println(heap);
13             }
14         }
15     }

 

写这个东西用了我四五个小时,因为时间有点晚了,明天还要上课,测试用例只准备了一组。运行正常,应当是没有问题的,不过最好还是准备几组数据自己测试一下。

转载请注明出处

以上是关于Java 堆接口和实现的主要内容,如果未能解决你的问题,请参考以下文章

Java 8 新特性总结

java中封装,继承,多态,接口学习总结

Java 封装

Java 封装

Java 封装

如何使用接口在片段和活动之间进行通信?