小顶堆基本概念及应用

package leetcode.heap;

/**
 * 小顶堆(即根节点小于或等于左右子树的值,且左右子树也为小顶堆) <br>
 * 堆是满二叉树,有特殊的性质
 * <ul>
 * <li>1、对于节点在i的元素,其左儿子在位置2i上,右儿子的2i+1上</li>
 * <li>2、父亲节点在i/2向下取整的位置上</li>
 * </ul>
 * 
 * @author li
 * 
 */
public class MinHeap {
    private int size;
    private final int MAX_CAPACITY;
    private int[] num;

    public int[] getNum() {
        return num;
    }

    public MinHeap(int capacity) {
        this.size = 0;
        this.MAX_CAPACITY = capacity;
        num = new int[MAX_CAPACITY + 1];
    }

    /**
     * 堆的插入: 采用向上过滤的方法<br>
     * 从数组的第二个元素进行插入
     * 
     * @param value
     * @throws Exception
     */
    public void insert(int value) throws Exception {
        if (size > MAX_CAPACITY) {
            throw new Exception("已经超出范围");
        }
        int i;
        for (i = (++size); num[i / 2] > value; i = i / 2) {
            num[i] = num[i / 2];
        }
        num[i] = value;
    }

    public int getMin() {
        return num[1];
    }

    /**
     * 删除堆顶元素 <br>
     * <ul>
     * <li>递归的找到每个节点左右子树的最小值</li>
     * <li>将该最小值填充到父节点</li>
     * </ul>
     * 
     * @throws Exception
     */
    public int deleteMin() throws Exception {
        if (size == 0) {
            throw new Exception("已经为空");
        }
        int LastElement = num[size--];// 获取最后一个元素,并且size-1
        int minElement = num[1];
        int child, i;
        for (i = 1; i * 2 <= size; i = child) {
            child = 2 * i;
            if (child != size && num[child + 1] < num[child]) {
                child++;// 右子树小于左子树
            }
            if (LastElement > num[child]) {
                num[i] = num[child];

            } else {
                break;
            }

        }
        num[i] = LastElement;
        return minElement;

    }

    public static void main(String[] args) {
        MinHeap minHeap = new MinHeap(5);
        try {
            minHeap.insert(4);
            minHeap.insert(2);
            minHeap.insert(3);
            minHeap.insert(2);
            minHeap.insert(2);
            int[] num = minHeap.num;
            for (int i = 0; i < num.length; i++) {
                System.out.println(num[i]);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}
package leetcode.heap;

/**
 * 
 * @author li
 * 
 */
public class FindMaxK {
    /**
     * 寻找最大的k个数<br>
     * 利用小顶堆来实现<br>
     * 建立k个节点的小顶堆<br>
     * 接着遍历,如果数字大于堆顶元素,则删除堆顶元素,并插入新的元素,遍历完成后堆中的元素即为最大的k个元素
     * 
     * @param num
     * @throws Exception
     */
    public int[] findMaxK(int[] num, int k) throws Exception {
        if (num.length <= k) {
            return num;
        }
        MinHeap minHeap = new MinHeap(k);
        for (int i = 0; i < k; i++) {
            minHeap.insert(num[i]);
        }
        for (int i = k; i < num.length; i++) {
            if (num[i] > minHeap.getMin()) {
                minHeap.deleteMin();
                minHeap.insert(num[i]);
            }
        }
        return minHeap.getNum();

    }

    public static void main(String[] args) {
        int[] num = { 4, 54, 32, 1, 4, 66, 87, 34 };
        try {
            int[] maxk = new FindMaxK().findMaxK(num, 4);
            for (int i = 1; i < maxk.length; i++) {
                System.out.println(maxk[i]);

            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
}

 

posted @ 2016-03-30 20:42  程序猿进化之路  阅读(1795)  评论(0)    收藏  举报