• 二叉堆


    二叉堆是完全二元树或者是近似完全二元树,按照数据的排列方式可以分为两种:大根堆和小根堆。
    大根堆(最大堆):父结点的键值总是大于或等于任何一个子节点的键值;小根堆(最小堆):父结点的键值总是小于或等于任何一个子节点的键值。

    二叉堆一般都通过”数组”来实现,下面是数组实现的最大堆和最小堆的示意图:

    代码实现

    大根堆

    public class MaxHeap<T extends Comparable<T>> {
    
        private List<T> mHeap;    // 队列(实际上是动态数组ArrayList的实例)
    
        public MaxHeap() {
            this.mHeap = new ArrayList<T>();
        }
    
        /* 
         * 最大堆的向下调整算法
         *
         * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
         *
         * 参数说明:
         *     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
         *     end   -- 截至范围(一般为数组中最后一个元素的索引)
         */
        protected void filterdown(int start, int end) {
            int c = start;          // 当前(current)节点的位置
            int l = 2*c + 1;     // 左(left)孩子的位置
            T tmp = mHeap.get(c);    // 当前(current)节点的大小
    
            while(l <= end) {
                int cmp = mHeap.get(l).compareTo(mHeap.get(l+1));
                // "l"是左孩子,"l+1"是右孩子
                if(l < end && cmp<0)
                    l++;        // 左右两孩子中选择较大者,即mHeap[l+1]
                cmp = tmp.compareTo(mHeap.get(l));
                if(cmp >= 0)
                    break;        //调整结束
                else {
                    mHeap.set(c, mHeap.get(l));
                    c = l;
                    l = 2*l + 1;   
                }       
            }   
            mHeap.set(c, tmp);
        }
    
        /*
         * 删除最大堆中的data
         *
         * 返回值:
         *      0,成功
         *     -1,失败
         */
        public int remove(T data) {
            // 如果"堆"已空,则返回-1
            if(mHeap.isEmpty() == true)
                return -1;
    
            // 获取data在数组中的索引
            int index = mHeap.indexOf(data);
            if (index==-1)
                return -1;
    
            int size = mHeap.size();
            mHeap.set(index, mHeap.get(size-1));// 用最后元素填补
            mHeap.remove(size - 1);                // 删除最后的元素
    
            if (mHeap.size() > 1)
                filterdown(index, mHeap.size()-1);    // 从index号位置开始自上向下调整为最小堆
    
            return 0;
        }
    
        /*
         * 最大堆的向上调整算法(从start开始向上直到0,调整堆)
         *
         * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
         *
         * 参数说明:
         *     start -- 被上调节点的起始位置(一般为数组中最后一个元素的索引)
         */
        protected void filterup(int start) {
            int c = start;            // 当前节点(current)的位置
            int p = (c-1)/2;        // 父(parent)结点的位置 
            T tmp = mHeap.get(c);        // 当前节点(current)的大小
    
            while(c > 0) {
                int cmp = mHeap.get(p).compareTo(tmp);
                if(cmp >= 0)
                    break;
                else {
                    mHeap.set(c, mHeap.get(p));
                    c = p;
                    p = (p-1)/2;   
                }       
            }
            mHeap.set(c, tmp);
        }
    
        /* 
         * 将data插入到二叉堆中
         */
        public void insert(T data) {
            int size = mHeap.size();
    
            mHeap.add(data);    // 将"数组"插在表尾
            filterup(size);        // 向上调整堆
        }
    
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            for (int i=0; i<mHeap.size(); i++)
                sb.append(mHeap.get(i) +" ");
    
            return sb.toString();
        }
    
        public static void main(String[] args) {
            int i;
            int a[] = {10, 40, 30, 60, 90, 70, 20, 50, 80};
            MaxHeap<Integer> tree=new MaxHeap<Integer>();
    
            System.out.printf("== 依次添加: ");
            for(i=0; i<a.length; i++) {
                System.out.printf("%d ", a[i]);
                tree.insert(a[i]);
            }
    
            System.out.printf("
    == 最 大 堆: %s", tree);
    
            i=85;
            tree.insert(i);
            System.out.printf("
    == 添加元素: %d", i);
            System.out.printf("
    == 最 大 堆: %s", tree);
    
            i=90;
            tree.remove(i);
            System.out.printf("
    == 删除元素: %d", i);
            System.out.printf("
    == 最 大 堆: %s", tree);
            System.out.printf("
    ");
        }
    }
    

    小根堆

    public class MinHeap<T extends Comparable<T>> {
    
        private List<T> mHeap;        // 存放堆的数组
    
        public MinHeap() {
            this.mHeap = new ArrayList<T>();
        }
    
        /* 
         * 最小堆的向下调整算法
         *
         * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
         *
         * 参数说明:
         *     start -- 被下调节点的起始位置(一般为0,表示从第1个开始)
         *     end   -- 截至范围(一般为数组中最后一个元素的索引)
         */
        protected void filterdown(int start, int end) {
            int c = start;          // 当前(current)节点的位置
            int l = 2*c + 1;     // 左(left)孩子的位置
            T tmp = mHeap.get(c);    // 当前(current)节点的大小
    
            while(l <= end) {
                int cmp = mHeap.get(l).compareTo(mHeap.get(l+1));
                // "l"是左孩子,"l+1"是右孩子
                if(l < end && cmp>0)
                    l++;        // 左右两孩子中选择较小者,即mHeap[l+1]
    
                cmp = tmp.compareTo(mHeap.get(l));
                if(cmp <= 0)
                    break;        //调整结束
                else {
                    mHeap.set(c, mHeap.get(l));
                    c = l;
                    l = 2*l + 1;   
                }       
            }   
            mHeap.set(c, tmp);
        }
    
        /*
         * 最小堆的删除
         *
         * 返回值:
         *     成功,返回被删除的值
         *     失败,返回null
         */
        public int remove(T data) {
            // 如果"堆"已空,则返回-1
            if(mHeap.isEmpty() == true)
                return -1;
    
            // 获取data在数组中的索引
            int index = mHeap.indexOf(data);
            if (index==-1)
                return -1;
    
            int size = mHeap.size();
            mHeap.set(index, mHeap.get(size-1));// 用最后元素填补
            mHeap.remove(size - 1);                // 删除最后的元素
    
            if (mHeap.size() > 1)
                filterdown(index, mHeap.size()-1);    // 从index号位置开始自上向下调整为最小堆
    
            return 0;
        }
    
        /*
         * 最小堆的向上调整算法(从start开始向上直到0,调整堆)
         *
         * 注:数组实现的堆中,第N个节点的左孩子的索引值是(2N+1),右孩子的索引是(2N+2)。
         *
         * 参数说明:
         *     start -- 被上调节点的起始位置(一般为数组中最后一个元素的索引)
         */
        protected void filterup(int start) {
            int c = start;            // 当前节点(current)的位置
            int p = (c-1)/2;        // 父(parent)结点的位置 
            T tmp = mHeap.get(c);        // 当前节点(current)的大小
    
            while(c > 0) {
                int cmp = mHeap.get(p).compareTo(tmp);
                if(cmp <= 0)
                    break;
                else {
                    mHeap.set(c, mHeap.get(p));
                    c = p;
                    p = (p-1)/2;   
                }       
            }
            mHeap.set(c, tmp);
        }
    
        /* 
         * 将data插入到二叉堆中
         */
        public void insert(T data) {
            int size = mHeap.size();
    
            mHeap.add(data);    // 将"数组"插在表尾
            filterup(size);        // 向上调整堆
        }
    
        public String toString() {
            StringBuilder sb = new StringBuilder();
            for (int i=0; i<mHeap.size(); i++)
                sb.append(mHeap.get(i) +" ");
    
            return sb.toString();
        }
    
        public static void main(String[] args) {
            int i;
            int a[] = {80, 40, 30, 60, 90, 70, 10, 50, 20};
            MinHeap<Integer> tree=new MinHeap<Integer>();
    
            System.out.printf("== 依次添加: ");
            for(i=0; i<a.length; i++) {
                System.out.printf("%d ", a[i]);
                tree.insert(a[i]);
            }
    
            System.out.printf("
    == 最 小 堆: %s", tree);
    
            i=15;
            tree.insert(i);
            System.out.printf("
    == 添加元素: %d", i);
            System.out.printf("
    == 最 小 堆: %s", tree);
    
            i=10;
            tree.remove(i);
            System.out.printf("
    == 删除元素: %d", i);
            System.out.printf("
    == 最 小 堆: %s", tree);
            System.out.printf("
    ");
        }
    }
    
  • 相关阅读:
    学习进度条
    0302我的感想
    1217实验四 递归下降语法分析程序设计
    1118 实验三 有限自动机的构造与识别
    1112我的访问与评论日记
    1014 我的C语言文法定义与C程序推导过程
    0917词法分析
    命令解释程序的编写
    构建之法前三章读后感
    复利计算4.0
  • 原文地址:https://www.cnblogs.com/Tu9oh0st/p/10318643.html
Copyright © 2020-2023  润新知