数据结构与算法-堆

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/zhangdong2012/article/details/99894675

堆的特点

  • 堆是一棵完全二叉树
  • 父节点大于子节点

堆的实现

package geektime.sort;

import java.util.ArrayList;
import java.util.List;

// 大顶堆
public class MaxHeap<E extends Comparable<E>> {

    private List<E> data;

    public MaxHeap() {
        this.data = new ArrayList<>();
    }


    public MaxHeap(E[] es) {
        this();
        buildHeap(es);
    }

    public void add(E e) {
        //将新数据添加到末尾
        this.data.add(e);
        //堆末尾元素进行上浮堆化
        siftUp(this.data.size(), this.data.size() - 1);
    }

    public E getMax() {
        return this.data.get(0);
    }

    //获取并删除堆定元素
    public E extractMax() {
        E max = this.data.get(0);
        swap(0, this.data.size() - 1);
        this.data.remove(this.data.size() - 1);
        siftDown(this.data.size(), 0);
        return max;
    }


    /**
     * 堆排序
     * */
    public void heapSort(){
        for (int i = this.data.size() - 1;i >=0;i --) {
            swap(0, i);
            siftDown(i, 0);
        }
    }


    private void buildHeap(E[] es) {
        //将元素添加到容器中
        for (E value : es) { this.data.add(value); }
        //找到第一个不是叶子节点到节点,堆其进行向下堆化
        for (int i = getParent(this.data.size() - 1);i >= 0;i --) {
            siftDown(this.data.size(), i);
        }
    }
    //上浮堆化
    private void siftUp(int len, int idx) {
        //如果当前节点值比父节点值大,那么进行交换,知道找到根节点
        while (getParent(idx) >= 0 && this.data.get(idx).compareTo(this.data.get(getParent(idx))) > 0) {
            swap(idx, getParent(idx));
            idx = getParent(idx);
        }
    }


    //下沉堆化
    private void siftDown(int len, int idx) {
        while (getLeft(idx) < len) {
            //找到左右节点中最大的那个
            int tempIdx = getLeft(idx);
            if (getRight(idx) < len && this.data.get(getRight(idx)).compareTo(this.data.get(tempIdx)) > 0) {
                tempIdx = getRight(idx);
            }

            //如果当前节点比两个子节点都打,那么就不需要后续都交换
            if(this.data.get(idx).compareTo(this.data.get(tempIdx)) > 0) {
                break;
            }else {
                swap(idx, tempIdx);
                idx = tempIdx;
            }
        }
    }



    private int getParent(int index) { return (index - 1) / 2; }
    private int getLeft(int index) { return index * 2 + 1; }
    private int getRight(int index) { return index * 2 + 2; }

    private void swap(int idx1, int idx2) {
        E temp = data.get(idx1);
        data.set(idx1, data.get(idx2));
        data.set(idx2, temp);
    }

    public void print() {
        data.stream().forEach(v -> System.out.print( v + " "));
        System.out.println();
    }


    public static void main(String[] args) {

        Integer[] arr = {1,5,2,6,8,3};
        MaxHeap<Integer> maxHeap = new MaxHeap<>(arr);
        //maxHeap.heapSort();
        maxHeap.print();//8 6 3 1 5 2
        maxHeap.add(0);
        maxHeap.add(55);
        maxHeap.print();//55 8 3 6 5 2 0 1
        System.out.println(maxHeap.extractMax());
        maxHeap.print();
        maxHeap.heapSort();
        maxHeap.print();//0 1 2 3 5 6 8 55

    }
}


用堆实现优先级队列

package geektime.sort;

public class PriorityQueue<E extends Comparable<E>> {

    private MaxHeap<E> maxHeap;
    public PriorityQueue() {
        this.maxHeap = new MaxHeap<>();
    }


    public void enqueue(E e) {
        this.maxHeap.add(e);
    }

    public E dequeue(){
        return this.maxHeap.extractMax();
    }


    public static void main(String[] args) {
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        queue.enqueue(1);
        queue.enqueue(2);
        queue.enqueue(3);

        System.out.println(queue.dequeue()); // 3
        System.out.println(queue.dequeue()); // 2
        System.out.println(queue.dequeue()); // 1
    }
}

时间复杂度

  • 插入元素 O(logN)
  • 删除元素 O(logN)
  • 排队 O(NlogN)

猜你喜欢

转载自blog.csdn.net/zhangdong2012/article/details/99894675