索引堆

索引堆是一种优化堆数据结构的方法,通过存储元素索引来减少大规模数据交换的成本。在索引堆中,我们对索引数组进行堆排序,而非原始数据,从而提供更快的查找和更新特定位置元素的能力,尤其适用于处理大型数据或需要频繁调整特定位置元素的情况。

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

什么是索引堆

索引堆是对堆这个数据结构的优化。

索引堆使用了一个新的int类型的数组,用于存放索引信息。

我们将会对索引数组进行堆排序,而不对数据直接进行堆排序。

相较于堆,优点如下:

1、优化了交换元素的消耗

如果堆中只放数字还好,但是如果存放的是大型字符串,经常交换会消耗很多资源。

2、加入的数据位置固定,方便寻找

比如我想在堆中给第七个进程提升优先级,那么我就需要直接去修改它。普通的堆因为要交换元素位置所以做不到这点。

建堆前:
在这里插入图片描述
建堆后:
在这里插入图片描述

代码如下

/**
 * @Author Nino 2019/11/25
 */
public class IndexMaxHeap<E extends Comparable<E>> {
    private E[] data; // 数据数组
    private int[] indexes; // 索引数组
    private int count;
    private int capacity;

    public IndexMaxHeap(int capacity) {
        this.capacity = capacity;
        count = 0;
        data = (E[]) new Comparable[capacity];
        indexes = new int[capacity];
    }

    /**
     * 插入新元素
     *
     * @param e 新元素的值
     */
    public void insert(E e) {
        data[count] = e;
        indexes[count] = count;
        siftUp(count++);
    }

    /**
     * 取出最大元素
     *
     * @return 最大的元素
     */
    public E extractMax() {
        E e = data[indexes[0]];
        count--;
        swapIndexes(0, count);
        siftDown(0);
        return e;
    }

    /**
     * 取出最大元素的索引
     *
     * @return 最大元素的索引
     */
    public int extractIndexMax() {
        int index = getMaxIndex();
        count--;
        swapIndexes(0, count);
        siftDown(0);
        return index;
    }

    /**
     * 将data中索引为i的元素替换成e
     *
     * @param i 替换位置的索引
     * @param e 替换后的值
     */
    public void change(int i, E e) {
        data[i] = e;

        // 寻找索引i对应的indexes索引数组的排名编号j
        // 即indexes[j] == i
        // 对这个位置j判断是否需要进行上浮以及下沉操作
        // 返回
        for (int j = 0; j < count; j++) {
            if (indexes[j] == i) {
                siftUp(j);
                siftDown(j);
                return;
            }
        }
    }

    public E getMax() {
        return data[indexes[0]];
    }

    public int getMaxIndex() {
        return indexes[0];
    }

    /**
     * 上浮操作
     * 比较的是data中的数据 但移动的是index数组
     *
     * @param index 需要上浮的位置
     */
    private void siftUp(int index) {
        while (index > 0 && data[indexes[index]].compareTo(data[indexes[getParent(index)]]) > 0) {
            swapIndexes(index, getParent(index));
            index = getParent(index);
        }
    }

    /**
     * 下沉操作
     * 比较的是data中的数据 但移动的是index数组
     *
     * @param index 需要下沉的位置
     */
    private void siftDown(int index) {
        while (getLeft(index) < count) {
            int toolMan = getLeft(index);
            if (getRight(index) < count && data[indexes[toolMan]].compareTo(data[indexes[getRight(index)]]) < 0) {
                toolMan += 1;
            }
            if (data[indexes[toolMan]].compareTo(data[indexes[index]]) <= 0) {
                break;
            }
            swapIndexes(index, toolMan);
            index = toolMan;
        }
    }

    private int getLeft(int index) {
        return index * 2 + 1;
    }

    private int getRight(int index) {
        return index * 2 + 2;
    }

    private int getParent(int index) {
        return (index - 1) / 2;
    }

    public int Size() {
        return count;
    }

    public boolean isEmpty() {
        return count == 0;
    }

    private void swapIndexes(int i, int j) {
        int temp = indexes[i];
        indexes[i] = indexes[j];
        indexes[j] = temp;
    }

	// 测试用例
    public static void main(String[] args) {
        IndexMaxHeap<Integer> heap = new IndexMaxHeap<>(10);
        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            heap.insert(random.nextInt(100));
        }
        for (int i = 0; i < 10; i++) {
            System.out.println(heap.extractMax());
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值