二叉树之堆

博客介绍了堆的相关知识,堆是一种二叉树,通常用顺序结构的数组存储,与操作系统虚拟进程地址空间中的堆不同。阐述了堆的概念,即节点值与父节点的关系及完全二叉树特性,还介绍了堆的实现,包括向下、向上调整建堆及堆的插入、查看、删除等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

TopK问题
在这里插入图片描述
现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。

1 、堆的概念
  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。
  • 按照层序遍历的结果储存在数组中
  • 堆的基本作用是快速找集合中的最值
    在这里插入图片描述
2、堆的实现
2.1堆向下调整建大堆

前提:左右子树必须已经是一个堆,才能调整,即只有一个不满足堆的性质

 //向下调整建大堆
    private static void CreateBig(int[] arr, int index) {
        //index就是要调整的parent
        int max = index * 2 + 1;
        /**
         * 保证有右孩子,再比较
         * 不是叶子结点,一定有左孩子,但不一定有右孩子
         * (1)没有右孩子,左边大
         * (2)有右孩子,左边大或者右边大
         * */
        //当有左孩子时执行以下
        while (max < arr.length) {
            //如果有右孩子,并且右孩子大于左孩子,改变max的值
            if (max + 1 < arr.length && arr[max + 1] > arr[max]) {
                max++;
            }
            //判断交换调整
            //当parent小于孩子时交换,否则不执行
            if (arr[index] < arr[max]) {
                int t = arr[max];
                arr[max] = arr[index];
                arr[index] = t;

                //改变index的max的值,使循环继续
                index = max;
                max = 2 * index + 1;
            } else {
                break;
            }
        }
    }


2.2堆向下调整建小堆

    //向下调整,建小堆
    private static void CreateSmall(int[] arr, int index) {
        //左孩子下标,代表 index 的最小值孩子的下标
        int min = index * 2 + 1;
        //1.有叶子结点
        while (min < arr.length) {
            //2.保证有右孩子的前提下,右孩子比较小
            //其他情况min就是最小的,即左孩子小
            if (min + 1 < arr.length && arr[min + 1] < arr[min]) {
                min++;
            }
            //3.根小于该孩子结点则不执行
            if (arr[index] <= arr[min]) {
                break;
            }
            //4.否则的话交换
            int t = arr[min];
            arr[min] = arr[index];
            arr[index] = t;
            //以该结点为根,继续向下调整
            index = min;
            min = 2 * min + 1;
        }
    }

2.3向上调整建大堆
 /* 向上调整为大堆 */
    @Override
    public void adjustUp(int[] array, int index) { 
       //index为插入的下标
       //父亲结点
        int parent = (index - 1) / 2;
        //一直调整到堆顶
        while (parent >= 0) {
            if (item[index] > item[parent]) {
                int t = item[index];
                item[index] = item[parent];
                item[parent] = t;
                index = parent;
                parent = (index - 1) / 2;
            } else {
                break;
            }
        }
    }

2.4建堆

给出一个数组,逻辑上是一个二叉树,但是还不是堆,从倒数的第一个非叶子节点的子树开始调整,一直调整到根节点的树,就可以调整成堆。
时间复杂度为O(N*logN),实际是O(N)

 private static void CreateHeap(int[] arr) {
        //从最后一个非叶子结点的下标开始
        for (int i = (arr.length - 1 - 1) / 2; i >= 0; i--) {
            //不断地做向下调整
            //CreateSmall(arr, i);
            CreateBig(arr,i);
        }
    }
2.3堆的插入、查看、删除
public class IHeapImpl implements IHeap {
    private int[] item;
    private int userSize;

    public IHeapImpl(int[] arr) {
        this.item =Arrays.copyOf(arr,arr.length);
      //  代表数组中被视为堆数据的个数
        this.userSize = 0;
    }

  /*  1.堆的插入  */ 
  
  //先插入一个数字到数组的尾上,长度++,再进行向上调整算法,直到满足堆。
    @Override
    public void add(int item) {
        if (Full()) {
            this.item = Arrays.copyOf(this.item, 2 * this.item.length + 1);
        }
        this.item[userSize] = item;
        this.userSize++;
        //加到最后一个了,所以要向上调整
        adjustUp(this.item, this.userSize - 1);
    }
 
    /* 向上调整为大堆 */
    @Override
    public void adjustUp(int[] array, int index) { 
       //index为插入的下标
       //父亲结点
        int parent = (index - 1) / 2;
        //一直调整到堆顶
        while (parent >= 0) {
            if (item[index] > item[parent]) {
                int t = item[index];
                item[index] = item[parent];
                item[parent] = t;
                index = parent;
                parent = (index - 1) / 2;
            } else {
                break;
            }
        }
    }

    @Override
    public int peek() {
        if (isEmpty()) {
            //不支持的异常
            throw new UnsupportedOperationException("堆为空");
        }
        return this.item[0];
    }

    //返回堆顶元素,并该数据元素
    //删除堆是删除堆顶的数据,将堆顶的数据根和最后一个数据一换,然后删除数组最后一个数据,再进行向下调整算法。
    @Override
    public int pop() {

        if (isEmpty()) {
            //抛出不支持的异常
            throw new UnsupportedOperationException("堆为空");
        }
        //先保留堆顶元素
        int old=this.item[0];
        //先交换,把堆顶元素和最后一个元素交换,最后一个元素下标为usedSize-1
        int t = this.item[0];
        this.item[0] = this.item[this.userSize - 1];
        this.item[this.userSize - 1] = t;

        //完了之后将交换后的最后一个元素删除,只要userSize--,说明下次做向下调整的时候就不走这里了
        this.userSize--;
        //此时只有0位值不满足堆的性质,向下调整建大堆
        adjustDown(this.userSize , 0);
        return old;
    }


    //向下调整
    @Override
    public void adjustDown(int len, int index) {
        int max = index * 2 + 1;
        while (max < len) {
            if (max + 1 < len && this.item[max] < this.item[max + 1]) {
                max++;
            }
            if (item[index] >= item[max]) {
                break;
            }
            int t = item[index];
            item[index] = item[max];
            item[max] = t;

            index = max;
            max = index * 2 + 1;
        }
    }

    //创建大根堆
    @Override
    public void createHeap(int[] array) {
        this.userSize=array.length;
        for (int i = (array.length - 1 - 1) / 2; i >= 0; i--) {
            adjustDown(this.userSize, i);
        }
    }

   
    @Override
    public void show() {
        for (int i = 0; i < this.userSize; i++) {
            System.out.print(item[i] + " ");
        }
    }

    @Override
    public boolean Full() {
        return this.userSize == this.item.length;
    }

    @Override
    public boolean isEmpty() {
        return this.userSize == 0;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值