Java-数据结构-小顶堆

介绍

是一种经过排序的完全二叉树,其中任一根节点的数据值均不大于其左子节点和右子节点的值。
则其root及根(堆顶)存储的就是整个堆中最小的值。

代码实现


/**
 * 小顶堆
 * 适用于在n个数中找最大的m个数字
 */
public class MinHeap {
    /**
     * 默认初始化长度
     */
    private static final  int  DEFAULT_INITIAL_CAPACITY = 10;
    /**
     * 当前堆长度
     */
    private int currentSize;
    /**
     * 堆的最大长度
     */
    private int capacity;
    /**
     * 数据域
     */
    private int[] queue;

    /**
     * 无参默认构造函数
     */
    public MinHeap()
    {
        initHeap(DEFAULT_INITIAL_CAPACITY);
    }

    /**
     * 有参构造
     * @param capacity  容量
     */
    public MinHeap(int capacity)
    {
        if(capacity<1||capacity>Integer.MAX_VALUE)
            throw new IndexOutOfBoundsException("非法长度");
        initHeap(capacity);
    }

    /**
     * 初始化堆
     * @param initCapacity  容量
     */
    private void initHeap(int initCapacity)
    {
        this.capacity = initCapacity;
        queue = new int[initCapacity];
        currentSize = 0;
    }

    /**
     * 添加一个元素
     * @param x 数据
     */
    public void add(int x)
    {
        //如果堆中没数据,则放到第一个
        if(currentSize==0) {
            queue[currentSize++] = x;
            //如果位置合法就会直接加入
        }else if(!isFull()) {
            adjustUP(currentSize++,x);
            //不合法会先进行判断然后
        } else {
            //如果栈顶比x小,则先移除,再再次尝试添加
            if(x>getTop()) {
                remove();
                add(x);
            }
        }
    }
    /**
     * 是否满堆
     * @return 若满返回true
     */
    public boolean isFull()
    {
        return currentSize>=capacity;
    }

    /**
     * 获得堆顶元素
     * @return
     */
    public int getTop()
    {
        return queue[0];
    }

    /**
     * 删除堆顶元素
     * @return  堆顶
     */
    public int remove()
    {
        //获得栈顶元素
        int cur = getTop();
        //获得最后一个元素
        int temp = queue[--currentSize];
        //将最后一个元素放到第一个
        queue[0] = temp;
        //进行调整
        adjustDown(0,temp);
        //返回栈顶元素
        return cur;
    }

    /**
     * 从下往上调整
     * @param k     需要调整的位置
     * @param value 需要调整的值
     */
   private void adjustUP(int k,int value)
   {
       //直到调整到k<=0及调整到堆顶0号下标
       while(k>0)
       {
           //获得父节点
           int root = (k-1)>>>1;
           //如果父节点的值小于等于要调整的值,说明符合小顶堆的要求,跳出
           if(queue[root]<=value)
           {
               break;
           }
           //如果父节点大于要调整的值,则需要将父节点往下移
           queue[k] = queue[root];
           //k往上移动
           k = root;
       }
       //将要调整的值放到k号位置
       queue[k] = value;
   }


    /**
     *从上往下调整
     * @param k     调整的位置
     * @param vale  调整的值
     */
    private void adjustDown(int k,int vale)
    {
        //调整的界限
        int half = currentSize>>>1;
        while (k<half)
        {
            //获得左孩子id
            int child = (k<<1)+1;
            //获得左孩子的值
            int childVal = queue[child];
            //获得右孩子id
            int RightChild = child+1;
            //先判断是否存在右孩子,再判断左孩子值大还是右孩子值大:目的是找到两个孩子中最小的放到childVal
            if(RightChild<currentSize && childVal>queue[RightChild])
            {
                childVal = queue[child = RightChild];
            }
            //如果孩子节点大于要调整的值,说明找到了正确位置,跳出
            if(childVal>vale)
            {
                break;
            }
            //如果没找到将小的孩子节点放到根节点
            queue[k] = queue[child];
            //k往下移动
            k = child;
        }
        //将值放入到k号位置
        queue[k] = vale;
    }

    /**
     * 打印当前的堆
     */
   public void print()
   {
       for (int i = 0; i < currentSize; i++) {
           System.out.print(queue[i]+" ");
       }
       System.out.println();
   }

    /**
     * 找出数组中最大的capacityge个数字
     * @param a 数组
     */
   public void add(int[] a)
   {
       for (int i = 0; i < a.length; i++) {
            add(a[i]);
       }
   }


}

实现难点

堆实现的难点主要在于其调整过程,每插入一个数据,或者删除一个数据都要对整个堆进行调整,使其符合小顶堆的要求。

猜你喜欢

转载自blog.csdn.net/qq_38345606/article/details/80951621