数据结构-堆

312 阅读1分钟

一、和普通队列比较

关键:动态

入队和队列一致, 出队的时候有一个优先级,优先级高的优先出队

二、时间复杂度比较

入队 出队(拿出最大元素)
普通线性结构 O(1) O(n)
顺序线性结构 O(n) O(1)
O(logn) O(logn)

三、堆 -Heap

二叉堆(Binary Heap)是一棵完全二叉树:

  1. 把一棵树的放完
  2. 某个节点总是不大于其parent节点 通常也叫最大堆

四、添加元素 -Sift Up

    // 向堆中添加元素
    public void add(E e){
        data.addLast(e);
        siftUp(data.getSize() - 1);
    }
    
    
    private void siftUp(int k){
        while(k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0 ){
            //交换和父亲节点的位置
            data.swap(k, parent(k));
            k = parent(k);
        }
    }

五、取出堆中的最大元素和Sift Down

  1. Sift Down
  2. 用最小元素替换堆顶元素,然后删除之前的最小元素位置
  3. 最小元素和子树中最大元素,比较,交换位置
  4. 下沉完毕
   // 看堆中的最大元素
    public E findMax(){
        if(data.getSize() == 0)
            throw new IllegalArgumentException("Can not findMax when heap is empty.");
        return data.get(0);
    }
    
取出最大元素
    // 取出堆中最大元素
    public E extractMax(){

        E ret = findMax();

        data.swap(0, data.getSize() - 1);
        data.removeLast();
        siftDown(0);

        return ret;
    }

下浮sift down
private void siftDown(int k){
    // k的左子树成为叶子节点
    // 在此轮循环中,data[k]和data[j]交换位置,也就是父亲节点和孩子节点进行交换
    while(leftChild(k) < data.getSize()){ 
        //j存储的是左孩子的索引
        int j = leftChild(k); 
        // j + 1 < data.getSize()说明有右孩子
        // j存储右孩子的索引(如果右比左大的话)
        if( j + 1 < data.getSize() &&
            data.get(j + 1).compareTo(data.get(j)) > 0 )
            //j ++ 后变成右孩子的索引
            j ++; 
        // data[j] 是 leftChild 和 rightChild 中的最大值
        if(data.get(k).compareTo(data.get(j)) >= 0 )
            break;

        data.swap(k, j);
        k = j;
    }
}