算法(6) 最大堆

普通队列:先进先出,后进后出

优先队列:出队顺序和入队顺序无关;和优先级有关

优先队列主要操作:

1.入队

2.出队:取出优先级最高的元素

 

二叉堆 Binary Heap

1.在二叉树上任何一个节点都不大于父亲节点

2.必须是一个完全的二叉树:除了最后一层的节点之外,其他层节点个数必须是最大值,最后一层可以不是最大值,但是最后一层的所有节点都必须集中在最左侧

 

满足以上两个性质的数据结构就是一个二叉堆 也叫做最大堆

最小堆:在二叉树上任何一个节点都不小于父亲节点

 

附上java版本数组实现的堆

import java.util.Random;

public class Main {

    /*
    *
    * 存入100000000个数据 然后选出前1000个大的数据
    * */
    public static void main(String[] args) {

        int capacity = 100000000;
        MaxHeap<Integer> maxHeap = new MaxHeap<>(capacity);
        Random random = new Random();
        for (int index = 0; index < capacity; index++) {
            maxHeap.insert(random.nextInt(10000));
        }
        long startTime = System.currentTimeMillis();

        //取出最大的5个元素
        for (int i = 0; i < 1000; i++) {
            Integer integer = maxHeap.extractMax();
        }

        System.out.println(System.currentTimeMillis() - startTime); // 耗时4ms
    }
}

/*
* 最大堆
*
*
* */
class MaxHeap<E extends Comparable<E>> {
    private E[] data;
    private int count;
    private int capacity;

    /*
    *最大容量
    *
    * */
    public MaxHeap(int capacity) {
        this.capacity = capacity;
        this.data = (E[]) new Comparable[capacity + 1];
    }


    public void insert(E e) {
        assert count + 1 <= capacity : "haha";

        data[count + 1] = e;
        count++;
        //新加入的元素有可能破坏了堆的定义 将count位置的元素进行重新排列
        shiftUp(count);

    }

    /*
    * 将K位置的元素尝试向上移动来重新将数组排列为一个堆
    * 将k 与 k / 2 两个元素进行比较 如果k 大于 k / 2 就交换两个位置上的元素,
    *
    *
    * */
    private void shiftUp(int k) {
        //当k为2或者相比较
        while (k > 1 && data[k].compareTo(data[k / 2]) > 0) {
            E temp = data[k];
            data[k] = data[k / 2];
            data[k / 2] = temp;
            k /= 2;
        }
    }

    public void print() {
        for (Comparable item : data) {
            System.out.print(item + " ");
        }
        System.out.println();

    }

    public E extractMax() {
        if (count <= 0) {
            return null;
        }
        E val = data[1];
        //交换位置
        data[1] = data[count];
        data[count] = null;
        count--;
        shiftDown(1);
        return val;
    }

    /*
    * 思路:
    * 1.先判断k元素是否有孩子
    * 2.没有就结束,有的话 再判断是否有两个孩子 比较出一个大的孩子
    * 3.将大的孩子与k进行交换
    * 4.继续重复123步骤
    * */
    private void shiftDown(int k) {
        int t;
        while ((t = 2 * k) <= count) {
            if (t + 1 <= count && data[t + 1].compareTo(data[t]) > 0) {//判断是否有右孩子
                t += 1;
            }
            if (data[k].compareTo(data[t]) > 0) {
                break;
            } else {//交换
                E temp = data[k];
                data[k] = data[t];
                data[t] = temp;
                k = t;
            }
        }
    }
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值