二叉堆是完全二叉树,每个结点中存有一个元素。
小根堆堆性质:父亲的权值不大于儿子的权值。
插入操作
插入操作是指向二叉堆中插入一个元素,要保证插入后也是一棵完全二叉树。
最简单的方法就是,最下一层最右边的叶子之后插入。
如果最下一层已满,就新增一层。
向上调整:如果这个结点的权值大于它父亲的权值,就交换,重复此过程直到不满足或者到根。
可以证明,插入之后向上调整后,没有其他结点会不满足堆性质。
向上调整的时间复杂度是log(n)。
删除操作
删除操作指删除堆中最大的元素,即删除根结点。
但是如果直接删除,则变成了两个堆,难以处理。
所以不妨考虑插入操作的逆过程,设法将根结点移到最后一个结点,然后直接删掉。
然而实际上不好做,我们通常采用的方法是,把根结点和最后一个结点直接交换。
于是直接删掉(在最后一个结点处的)根结点,但是新的根结点可能不满足堆性质
向下调整:在该结点的儿子中,找一个最小的,与该结点交换,重复此过程直到底层。
可以证明,删除并向下调整后,没有其他结点不满足堆性质。
时间复杂度log(n) 。
应用:
寻找数组中第K个最小的元素
BinHeapMin.h
#pragma once
#include
class BinHeapMin
{
public:
BinHeapMin();
~BinHeapMin();
bool Insert(int k);
bool Delete(int k);
int GetIndex(int k);
void show();
private:
static const int CAPACITY;
int *prique;
int size;
};
const int BinHeapMin::CAPACITY = 100;
BinHeapMin::BinHeapMin()
{
prique = new int[CAPACITY];
size = 0;
}
BinHeapMin::~BinHeapMin()
{
if (prique != nullptr)
{
delete[] prique;
prique = nullptr;
}
}
bool BinHeapMin::Insert(int k)
{
if (size >= CAPACITY)
return false;
//percolate up
int parent = (size - 1) / 2;
int curIndex = size;
while (curIndex > 0 && k <= prique[parent])
{
prique[curIndex] = prique[parent];
curIndex = parent;
parent = (parent - 1) / 2;
}
prique[curIndex] = k;
++size;
return true;
}
int BinHeapMin::GetIndex(int k)
{
if (size == 0)
return -1;
for (int i = 0; i < size; ++i)
if (prique[i] == k )
return i;
return -1;
}
bool BinHeapMin::Delete(int k)
{
if (size == 0)
return false;
int targetIndex = GetIndex(k);
if (targetIndex < 0)
return false;
int lastElem = prique[--size];
//percolate down
int child = 2 * targetIndex + 1;
int parent = targetIndex;
while (child < size)
{
// find smaller child
if ((child + 1) < size && prique[child] > prique[child + 1])
++child;
// percolate one level
if (lastElem > prique[child])
prique[parent] = prique[child];
else
break;
parent = child;
child = 2 * child +1;
}
prique[parent] = lastElem;
return true;
}
void BinHeapMin::show()
{
for (int i = 0; i < size; ++i)
std::cout << prique[i] << " ";
std::cout << std::endl;
}
BinHeapMin.cpp
#include "BinHeapMin.h"
int main()
{
BinHeapMin prique;
int arr[] = { 13, 14, 16, 19, 21, 19, 68, 65, 26, 32, 31 };
for (int i = 0; i < sizeof(arr) / sizeof(int); ++i)
{
prique.Insert(arr[i]);
}
prique.show();
std::cout << "After delete 13" << std::endl;
prique.Delete(13);
prique.show();
return 0;
}
13 14 16 19 21 19 68 65 26 32 31
After delete 13
14 19 16 26 21 19 68 65 31 32