堆有别于一般的树,它是为了实现“每次取出最大值或最小值”的操作而创造出的一种有显著特征的树。
最大堆的最大特征,是它的每个结点都比它任意一个子节点要大。换言之,即每一棵子树也同样是一个最大堆。而且堆还是一个完全二叉树,这也方便了对堆的操作。
堆的插入:由于元素的相对大小是未知的,而树在元素插入的前后都是一个最大堆,因此在插入操作中,最重要的一步就是让新插入的元素找到对应的位置,同时保持它经过的子树仍然是一个最大堆。这里采用的方法是先把元素插在完全二叉树最后一个元素的下一个位置,之后一路与它的父节点比较大小。若是新元素大,则二者交换位置。这里由于每一次与新元素并列的另一个子节点是一定比父节点小的,因此只需要考虑新元素与其父节点的大小关系即可。循环的结束条件是找到了一个比新元素大的父节点,或者新元素到达了根节点的位置。对于是否处在根节点的判断,可以使用对下标的限制来实现,或者在[0]的位置放置一个一定比元素大的哨兵。
堆的删除:同理,删除操作也需要保持删除前后的树是最大堆。堆的特性决定了它每次删除的元素都是堆的最大的元素,也是堆的根节点。此时堆内的元素数量减一,因此把堆中编号最后的元素拿出来,先放在根节点的位置。之后每次与它的两个子节点作比较,与子节点中较大的且比该元素大的节点交换位置。直到该元素比子节点都大或者没有子节点了为止。
代码如下。
//最大堆
struct hp
{
int* values;
int size; //当前长度
int capacity; //容量
};
class test002
{
public:
hp* createheap(int maxsize, int maxvalue)
{
hp* H = (hp*)malloc(sizeof(struct hp));
H->values = (int*)malloc((maxsize + 1) * sizeof(int*));
H->capacity = maxsize;
H->size = 0;
H->values[0] = maxvalue;
return H;
}
void insertheap(int value, hp* H)
{
if (H->capacity == H->size)
{
cout << "该最大堆已满" << endl;
return;
}
int i = 0;
i = ++H->size;
for (;value > H->values[i / 2];i /= 2)
{
H->values[i] = H->values[i / 2];
}
H->values[i] = value;
}
int deleteheap(hp* H)
{
if (H == NULL)
{
cout << "该最大堆已为空" << endl;
return 0;
}
int dad;
int son;
int maxnum;
int temp;
maxnum = H->values[1];
temp = H->values[H->size];
H->size -= 1;
for (dad = 1;dad * 2 <= H->size;dad = son)
{
son = dad * 2;
if (son != H->size && H->values[son] < H->values[son + 1])
{
son += 1;
}
else
{
son = son;
}
if (temp > H->values[son])
{
break;
}
else
{
H->values[dad] = H->values[son];
H->values[son] = temp;
}
}
return maxnum;
}
};