【算法百题之十四】大顶堆的实现
大家好,我是Lampard~~
很高兴又能和大家见面了,接下来准备系列更新的是算法题,一日一练,早日升仙!
今天的问题是:
实现大顶堆。对于堆大家都不陌生,分为大顶堆和小顶堆。
它是逻辑上以一种完全二叉树的形式,实际上凭借数组实现的一个数据结构。
那么我们今天要实现的大顶堆是要求父亲结点要比孩子结点的值要大:
大顶堆的类:
class BigHeap
{
private:
vector<int> array ;
int length;
public:
BigHeap();
void Insert(int data); // 插入
void Delete(int data); // 删除
void swim(int location);// 上浮
void down(int location);// 下沉
void show();
};
这个类很简单,分为插入,删除,上浮,下沉四个函数。
并且有两个私有属性,一个是堆的存储向量array,一个是代表当前向量索引的length。
首先是插入的实现:
void BigHeap::Insert(int data) // 删除
{
if (length == 1)
{
array.push_back(data) ;
length++;
}
else if (length > 1 )
{
array.push_back(data);
if (array[length] > array[length / 2])
{
swim(length);
}
length++;
}
}
可以看到,我们是从索引array【1】开始存放数据的。
这样做的好处是可以通过2*索引找到它的左孩子,2*索引加1,找到他的右孩子
如果孩子比父亲小我们就直接插入,如果比父亲大我们就和父亲交换位置
并通过swim上浮函数递归判断比不比自己的祖辈大
上浮函数的实现:
void BigHeap::swim(int location) // 上浮操作
{
swap(array[location], array[location / 2]);
if (location / 4 > 0 && array[location / 2] > array[location / 4])
swim(location / 2);
}
如果有爷爷的话就继续判断,如果没有爷爷就只和父亲交换位置就行了
删除函数的实现:
void BigHeap::Delete(int data)
{
int flag = 0;
for (int i = 1; i < length; i++)
{
if (array[i] == data)
{
flag = i;
break;
}
}
if (flag == 0)
cout << "不存在数据为:" << data << " 的数据" << endl;
else if (flag == length - 1)
array.pop_back();
else if(flag != length -1 && flag != 0)
{
swap(array[flag], array[length - 1]);
array.pop_back();
length--;
down(flag);
}
}
首先我们遍历找到我们要删除的位置,然后判断是否为最后一个元素,是的话直接删除
如果不是最后一个元素的话,就和最后一个元素交换位置,删除最后一个元素
然后判断原位置是不是为叶子结点,如果是叶子结点就不需要下沉操作,
如果不是叶子结点的话就递归进行下沉操作。
下沉函数:
void BigHeap::down(int location)
{
if (location * 2 > length - 1) // 没有孩子
return;
else if (location * 2 + 1 <= length - 1) // 有左右孩子
{
if (array[location * 2] < array[location * 2 + 1])
{
swap(array[location], array[location * 2 + 1]);
down(location * 2 + 1);
}
else if (array[location * 2] > array[location * 2 + 1])
{
swap(array[location], array[location * 2]);
down(location * 2);
}
}
else if (location * 2 == length - 1) // 有左孩子没右孩子
{
swap(array[location], array[location * 2]);
}
}
最后是测试函数:
int main()
{
int array[] = {4,2,5,7,9,8,6,1,3,0};
BigHeap* Bheap = new BigHeap();
for (int i = 0; i < sizeof(array) / sizeof(array[0]); i++)
{
Bheap->Insert(array[i]);
}
Bheap->show();
cout << "现在删除结点7" << endl;
Bheap->Delete(7);
Bheap->show();
}
手写版的预估结果:
插入:
删除:
测试结果: