什么是索引堆
索引堆是对堆这个数据结构的优化。
索引堆使用了一个新的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());
}
}
}