自定义代码实现简单堆

此简单堆为最大堆,根结点元素最大,每个父结点都大于或等于其左右子结点
简单堆功能

  1. 获取堆中存储元素的个数 length()
  2. 交换堆中索引i与j处的值
  3. 往堆中插入新的元素
public class Heap<T extends Comparable<T>> {

    //存储堆中的元素数组
    private T[] items;
    //记录堆中元素的个数
    private int N;

    //构造方法
    public Heap(int capacity){
        //指定堆存储元素的初始容量,索引0位置不存储元素 所以要将指定容量+1 指定数组容量
        this.items=(T[]) new Comparable[capacity+1];
        //初始化堆中存储元素的个数
        this.N=0;
    }


    /**
     * 获取堆中存储元素的个数
     * @return
     */
    public int length(){
        return N;
    }
    /**
     * 改变数组容量 为指定容量
     * @param newSize 指定的数组容量
     *
     */
   public void resize(int newSize){
        //创建一个新数组 指向items
       T[] temp = items;
       //创建新数组指定长度赋值给items
       items=(T[]) new Comparable[newSize+1];
       //将temp中的数据重新存入容量改变后的items中
       for (int i = 1; i <=N; i++) {
           items[i]=temp[i];
       }
   }

    /**
     * 判断索引i处的值是否小于索引j出的值
     * @param i 索引i
     * @param j 索引j
     * @return true items[i]<items[j]  false items[i]>items[j]
     */
   public boolean less(int i,int j){
       return items[i].compareTo(items[j])<0;
   }

    /**
     * 交换索引i与j对应的值
     * @param i
     * @param j
     */
   public void exchange(int i,int j){
       T temp=items[i];
       items[i]=items[j];
       items[j]=temp;
   }

    /**
     * 往堆中插入一个新元素
     * @param t
     */
   public void insert(T t){
       //将新元素存储到数组的已有元素的尾部
       items[++N]=t;
       //并调用上浮算法 将该元素调整至合适的位置
       swim(N);
   }

    /** 完成真正的插入元素动作
     *  添加元素时默认将新元素插入到数组最后元素的后一个位置,将新元素索引位置的元素上浮到堆中正确的位置
     * @param k
     */
   private void swim(int k){
        if(k==1){
        //元素在根结点不用调整位置
            return;
        }
    //索引不为根结点
        if(!less(k,k/2)){
           //当前索引位置的元素比其父结点所在索引位置的元素大交换二者位置
           exchange(k,k/2);
           //递归调用继续寻找正确位置
           swim(k/2);
        }
       //当前索引位置的元素比其父结点所在索引位置的元素小保持当前位置不做改变
   }

    /**
     * 删除堆中最大的元素,并返回这个最大的元素
     * @return
     */
   public T deleteMax(){
       //创建变量
       T temp=items[1];
       //交换索引1与索引N的值,让完全二叉树最右侧的元素变为临时根结点
       exchange(1,N); //递归实现时不需要
       //删除最大元素
       items[N]=null; //递归实现时不需要
       //元素个数-1
       N--;
       //使索引1的临时根结点元素下沉到正确位置
       sink(1);
       //返回删除的值
       return temp;
   }

    /** 完成真正的元素删除动作
     * 删除时将最大元素items[1]与堆中最后一个元素items[N-1]交换值 并让items[N-1]为null 就代表了删除了原先的最大元素
     * 下沉算法,使得新的根结点的值与其左右子结点进行比较并交换位置
     * @param k
     */
   private void sink(int k){
       while (2*k<=N){
           int max;//记录左右子结点中元素较大的索引
           //当前结点存在左子结点
           if (2*k+1<=N){
               //当前结点存在右子结点 ,则当前节点结点的元素与左右子结点中较大的进行比较
               if (less(2*k,2*k+1)){
                   //左子结点的元素小于右子结点的元素 记录max为右子结点索引
                   max=2*k+1;
               }else {
                   //左子结点的元素大于右子结点的元素 记录max为左子结点索引
                   max=2*k;
                   }
           }else {
               //右子结点不存在 当前结点只需要与左子结点比较
               max=2*k;
           }
           //比较当前结点与左右子结点中较大者的大小
           if (!less(k,max)){
               //当前结点元素大于元素值较大的结点,不用交换位置并结束循环
               break;
           }
           //当前结点元素小于元素值较大的结点,交换位置
           exchange(k,max);
           k=2*k;
       }

       //递归方式实现
//       if (items[k*2]==null){
//           //结点k无左右子结点,那么结点k的值赋值为null
//           items[k]=null;
//           return;
//       }
//       //当前结点有左子结点
//       if (items[k*2+1]==null){
//           //当前结点的右子结点为null 当前结点的值变为其左子结点的值
//           items[k]=items[k*2];
//           //继续递归调用 使左子结点值为正确的值
//           sink(k*2);
//       } else
//       if (less(k*2,k*2+1)){
//           //存在右子结点,当前结点的左子结点小于右子结点,当前结点的值变为其右子结点的值
//           items[k]=items[k*2+1];
//           //继续递归调用 使右子结点的值为正确值
//           sink(k*2+1);
//       }else {
//           //左子结点大于右子结点,当前结点的值变为其左子结点的值
//           items[k]=items[k*2];
//           sink(k*2);
//           if(items[k*2]==null) {
//               items[k*2]=items[k*2+1];
//               items[k*2+1]=null;
//           }
//       }
   }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值