最小堆 :完全二叉树,能方便地从中取出最小/大元素

/**        
 * Title: 最小堆 :完全二叉树,能方便地从中取出最小/大元素   
 * Description: 
 * 堆的构建
 * 堆的打印(前序遍历的应用)
 * 堆的插入(插入到堆尾,再自下向上调整为最小堆)
 * 堆的删除(删除堆顶元素并用堆尾元素添补,再自上向下调整为最小堆)
 * 堆排序(时间复杂度:O(nlgn),空间复杂度O(1),不稳定):升序排序一般用最大堆
 */      
public class MinHeap  {
        private int[] heap;  // 将所有元素以完全二叉树的形式存入数组
        private int size;  // 堆中元素的个数

        /**
        * 构造函数
        * 
        * @description 构建一个大小为size的最小堆
        * @param size
        */
        public MinHeap(int maxSize)  {
            heap = new int[maxSize];
        }

        /**
        * 构造函数
        * 
        * @description 基于数组构造最小堆
        * @param arr
        */
        public MinHeap(int[] arr, int maxSize)  {
                heap = new int[maxSize > arr.length ? maxSize : arr.length];
                System.arraycopy(arr, 0, heap, 0, arr.length);
                size = arr.length;

                int pos = (size - 2)  /  2; // 最初调整位置:最后的分支节点(最后叶节点的父亲)
                while (pos >= 0)  {    // 依次调整每个分支节点
                shiftDown(pos, size - 1);
                pos--;
            }
        }

        /**
        * @description 自上向下调整为最小堆(从不是最小堆调整为最小堆),调整的前提是其左子树与右子树均为最小堆
        * @param start
        * @param end
        */
        private void shiftDown(int start, int end)  {
            int i = start;    // 起始调整位置,分支节点
            int j = 2 * start + 1;  // 该分支节点的子节点
            int temp = heap[i];   
            while  (j <= end)  {  // 迭代条件:子节点不能超出end(范围)
            if  (j < end)  { 
            j = heap[j] > heap[j + 1] ? j + 1 : j; // 选择两孩子中较小的那个
            }
            if  (temp  <  heap[j])  {   // 较小的孩子大于父亲,不做任何处理
            break;
            } 
            else  {    // 否则,替换父节点的值
                heap[i] = heap[j];  
                i = j;
                j = 2 * j + 1;
            }
        }
        heap[i] = temp;  // 一步到位
    }

    /**     
    * @description 自下向上调整为最小堆(原来已是最小堆,添加元素后,确保其还是最小堆)   
    * @param start     
    */
    private void shiftUp(int start)  {
        int j = start;
        int i = (j - 1)  /  2;   // 起始调整位置,分支节点
        int temp = heap[j];
        while  (j > 0)  {      // 迭代条件:子节点必须不为根
            if  (temp >= heap[i])  {  //原已是最小堆,所以只需比较这个子女与父亲的关系即可
            break;
            } 
            else  {
                heap[j] = heap[i];
                j = i;
                i = (j - 1) / 2;
            }
        }
        heap[j] = temp;   // 一步到位
    }


    /**
    * @description 向最小堆插入元素(总是插入到最小堆的最后)
    * @param data
    */
    public void insert(int data) {
        if  (size < heap.length)  {
            heap[size++] = data;   // 插入堆尾
            shiftUp(size-1);   // 自下而上调整
        }
    }

    /**     
    * @description 删除堆顶元素,以堆的最后一个元素填充          
    */
    public void remove()  {
            if  (size > 0)  {
                heap[0] = heap[size-1];   // 删除堆顶元素,并将堆尾元素回填到堆顶
                size --;   // 堆大小减一
                shiftDown(0, size-1);   // 自上向下调整为最小堆
            }
    }

    /**     
    * @description 堆排序:每次将最小元素交换到最后        
    */
    public void sort() {
        for  (int i = size - 1; i >= 0; i--)  {
                int temp = heap[0];
                heap[0] = heap[i];
                heap[i] = temp;

                shiftDown(0, i-1);
        }

        for  (int i = size-1; i >= 0; i--)  {
            System.out.print(heap[i] + " ");
        }
    }

    /**
    * @description 打印根为 i 的最小堆
    * @param i
    */
    public void printMinHeap(int i)  {
        if  (size > i)  {
            System.out.print(heap[i]);
            if  (2 * i + 1 < size || 2 * i + 2 < size)  {
                System.out.print("(");
                printMinHeap(2 * i + 1);
                System.out.print(",");
                printMinHeap(2 * i + 2);
                System.out.print(")");
            }
        }
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值