数据结构--堆

作者: 良辰美景TT | 来源:发表于2018-09-27 13:44 被阅读3次

    堆有两个特性:

    • 堆是一个完全二叉树
    • 堆中所有父节点都大于(最大堆)或者小于(最小堆)子结点。
      在一般的实现中,我们可以用数组来存储堆中的元素,数组的索引用于实现结点左右孩子的查找。
      最小堆的实现代码如下:
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    
    /**
     * 
     * 功能描述: 最小堆的实现
     * 
     * @version 2.0.0
     * @author zhiminchen
     */
    public class MinHeap<E extends Comparable<E>> {
    
        // 用于存储数据E对象
        private E[] data;
        // 当前数组已经存储了多少个数据
        private int size;
    
        public MinHeap(int capacity) {
            data = (E[]) new Comparable[capacity];
            size = 0;
        }
    
        public MinHeap() {
            this(16);
        }
    
        /**
         * 传入一个array数组,构造堆
         * 
         * @param array
         */
        public MinHeap(E[] array) {
            data = (E[]) new Comparable[array.length];
            // 将array数据复制到data数组中
            for (int i = 0; i < data.length; i++) {
                data[i] = array[i];
            }
            size = array.length;
            // 对堆中非叶子结点做siftDown操作, 这样堆的特性就维护好了
            for (int i = parent(array.length - 1); i >= 0; i--) {
                siftDown(i);
            }
        }
    
        /**
         * 
         * 功能描述: 堆是否为空的方法
         * 
         * @return boolean
         * @version 2.0.0
         * @author zhiminchen
         */
        public boolean isEmpty() {
            return size == 0;
        }
    
        /**
         * 
         * 功能描述: 返回当前堆的大小
         * 
         * @return int
         * @version 2.0.0
         * @author zhiminchen
         */
        public int size() {
            return size;
        }
    
        /**
         * 
         * 功能描述: 得到index的父亲结点
         * 
         * @param index
         * @return int
         * @version 2.0.0
         * @author zhiminchen
         */
        private int parent(int index) {
            if (index == 0)
                throw new IllegalArgumentException("index-0 doesn't have parent.");
            return (index - 1) / 2;
        }
    
        /**
         * 
         * 功能描述: 得到index的左孩子结点
         * 
         * @param index
         * @return int
         * @version 2.0.0
         * @author zhiminchen
         */
        private int left(int index) {
            return 2 * index + 1;
        }
    
        /**
         * 
         * 功能描述: 得到index下的右孩子结点
         * 
         * @param index
         * @return int
         * @version 2.0.0
         * @author zhiminchen
         */
        private int right(int index) {
            return 2 * index + 2;
        }
    
        /**
         * 
         * 功能描述: 往堆中增加元素element
         * 
         * @param element void
         * @version 2.0.0
         * @author zhiminchen
         */
        public void add(E element) {
            if (size >= data.length) {
                resize(data.length * 2);
            }
    
            data[size] = element;
    
            siftUp(size);
            size++;
        }
    
        /**
         * 
         * 功能描述: 删除堆顶的元素,并返回
         * 
         * @return E
         * @version 2.0.0
         * @author zhiminchen
         */
        public E remove() {
            if (size <= 0) {
                return null;
            }
            E ret = data[0];
            // 将数组的最后一个元素放到队列的头
            data[0] = data[size - 1];
            data[size - 1] = null;
            // 对size进行维护
            size--;
            // 对零位的数据进行下沉操作, 以保持堆的特性
            siftDown(0);
            return ret;
        }
    
        /**
         * 
         * 功能描述: 查看堆中最小的元素
         * 
         * @return E
         * @version 2.0.0
         * @author zhiminchen
         */
        public E findMin() {
            if (size == 0)
                throw new IllegalArgumentException("Can not findMin when heap is empty.");
            return data[0];
        }
    
        /**
         * 
         * 功能描述: 对index的元素进行下沉操作,以保持推的特性
         * 
         * @param index void
         * @version 2.0.0
         * @author zhiminchen
         */
        private void siftDown(int index) {
            int left = left(index);
            // 递归退出条件 left>=size说明当前节点已经是叶子节点了
            if (left >= size) {
                return;
            }
            // 假设index的左节点是最小的节点
            E min = data[left];
            // 如果index节点有右孩子并且右孩子比左孩子还小, index结点需要跟最小的节点进行交换
            if (left + 1 < size && min.compareTo(data[left + 1]) > 0) {
                min = data[left + 1];
                left = left + 1;
            }
            // 当index节点的数据比最小的节点还大的时候,则进行交换,否则结束
            if (data[index].compareTo(min) > 0) {
                swap(index, left);
                siftDown(left);
            }
        }
    
        /**
         * 
         * 功能描述: 对index元素进行上浮操作, 以维持队的特性
         * 
         * @param size2 void
         * @version 2.0.0
         * @author zhiminchen
         */
        private void siftUp(int index) {
            // 递归退出的条件
            if (index <= 0) {
                return;
            }
            // index节点比父亲节点小, 则进行上浮
            if (data[index].compareTo(data[parent(index)]) < 0) {
                swap(index, parent(index));
                // 递归调用,继续上浮
                siftUp(parent(index));
            }
        }
    
        /**
         * 
         * 功能描述: 交换索引为a, b的数据
         * 
         * @param a
         * @param b void
         * @version 2.0.0
         * @author zhiminchen
         */
        private void swap(int a,
                          int b) {
            E temp = data[a];
            data[a] = data[b];
            data[b] = temp;
        }
    
        /**
         * 
         * 功能描述: 对堆进行扩容
         * 
         * @param capacity void
         * @version 2.0.0
         * @author zhiminchen
         */
        private void resize(int capacity) {
            E[] temp = (E[]) new Object[capacity];
            for (int i = 0; i < data.length; i++) {
                temp[i] = data[i];
            }
            data = temp;
        }
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append(String.format("heap size : %d capacity : %d ", size, data.length));
            sb.append("[");
            for (int i = 0; i < size; i++) {
                sb.append(data[i]);
                if (i != size - 1) {
                    sb.append(", ");
                }
            }
            sb.append("]");
            return sb.toString();
        }
    
        public static void main(String[] args) {
            Random random = new Random();
            int n = 100;
            Integer array[] = new Integer[n];
            for (int i = 0; i < 100; i++) {
                array[i] = random.nextInt(Integer.MAX_VALUE);
            }
    
            MinHeap<Integer> heap = new MinHeap<Integer>(array);
    
            System.out.println(heap);
    
            List<Integer> list = new ArrayList<Integer>();
            while (!heap.isEmpty()) {
                list.add(heap.remove());
            }
    
            for (int i = 1; i < list.size(); i++) {
                if (list.get(i - 1) > list.get(i)) {
                    throw new RuntimeException();
                }
            }
    
        }
    }
    
    

    相关文章

      网友评论

        本文标题:数据结构--堆

        本文链接:https://www.haomeiwen.com/subject/tfdjoftx.html