【注意】索引堆的实现是建立在堆排序的基础上,还不了解堆排序的柚子,可以参考我的这篇博客二叉堆(最大堆)之堆排序
【代码实现】
#include <iostream>
#include <cassert>
#include <algorithm>
#include <ctime>
#include <string>
#include <cmath>
#include <typeinfo>
#include <cstring>
using namespace std;
template<typename Item>
class HeapIndexMax
{
private:
Item *data; //存放数据的数组
int*index; //存放索引的数组
int count; //数据元素的个数
int capacity; //初始化数组时的数组大小
void shiftUp(int k)
{
while(k > 1 && data[index[k]] > data[index[k / 2]])
{
swap(index[k], index[k / 2]);
k /= 2;
}
}
void shiftDown(int k)
{
while(k * 2 <= count)
{
int j = k * 2;
while(j + 1 <= count && data[index[j + 1]] > data[index[j]])
{
j = j + 1;
}
if(data[index[k]] > data[index[j]])
{
break;
}
swap(index[k], index[j]);
k = j;
}
}
public:
HeapIndexMax(int capacity)
{
data = new Item[capacity + 1];
index = new int[capacity + 1];
count = 0;
this->capacity = capacity;
}
//传入的 i 对于用户而言,是从0开始的
void insert(int i, Item item)
{
assert(count + 1 <= capacity);
assert(i + 1 >= 1 && i + 1 <= capacity);
i += 1;
index[count + 1] = i;
data[i] = item;
count++;
shiftUp(count);
}
Item extractMax()
{
assert(count > 0);
Item ret = data[index[1]];
swap(index[1], index[count]);
count--;
shiftDown(1);
return ret;
}
//返回最大元素的索引
int extractIndexMax()
{
assert(count > 0);
int ret = index[1] - 1;
swap(index[1], index[count]);
count--;
shiftDown(count);
return ret;
}
//返回索引为i的数据
Item getItem(int i)
{
return data[i + 1];
}
//希望将索引为i的元素的值修改为 newItem
void change(int i, Item newItem)
{
i += 1;
data[i] = newItem;
//要找到index[j] = i 的这个j,这个j表示data[i] 在堆中的位置
//再shiftUp(j) 和shiftDown(j)
for(int j = 1; j <= count; j++)
{
if(index[j] == i)
{
shiftUp(j);
shiftDown(j);
return;
}
}
}
~HeapIndexMax()
{
delete[] data;
delete[] index;
}
};
【算法分析】
//希望将索引为i的元素的值修改为 newItem
void change(int i, Item newItem)
{
i += 1;
data[i] = newItem;
//要找到index[j] = i 的这个j,这个j表示data[i] 在堆中的位置
//再shiftUp(j) 和shiftDown(j)
for(int j = 1; j <= count; j++)
{
if(index[j] == i)
{
shiftUp(j);
shiftDown(j);
return;
}
}
}
在上面的change函数中,我们来分析一下时间复杂度。一层for循环是O(n)级别的,一次shiftUp和shiftDown是O(logn)级别的,所以change函数的时间复杂度为O(n)。但是我们整个堆排序的时间复杂度为O(logn),那我们有没有办法将change函数的时间复杂度降为O(logn)呢?
请看下回讲解~