上次说到向libevent小根堆中添加事件,这次来说一下删除事件:
假如堆中的数据是这样儿存放滴:
现在删除值为31的元素,看删除的代码:
void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
{
unsigned parent = (hole_index - 1) / 2; /* 父节点 */
while(hole_index && min_heap_elem_greater(s->p[parent], e)) //s->[parent] > e
{
(s->p[hole_index] = s->p[parent])->min_heap_idx = hole_index;
hole_index = parent;
parent = (hole_index - 1) / 2;
}
(s->p[hole_index] = e)->min_heap_idx = hole_index;
}
void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
{
unsigned min_child = 2 * (hole_index + 1); /* 要删除元素的右儿子 */
while(min_child <= s->n)
{ /* get 小儿子 */
min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
if(!(min_heap_elem_greater(e, s->p[min_child])))
break;
(s->p[hole_index] = s->p[min_child])->min_heap_idx = hole_index;
hole_index = min_child;
min_child = 2 * (hole_index + 1);
}
min_heap_shift_up_(s, hole_index, e);
}
int min_heap_erase(min_heap_t* s, struct event* e)
{
if(((unsigned int)-1) != e->min_heap_idx)
{
struct event *last = s->p[--s->n];
unsigned parent = (e->min_heap_idx - 1) / 2;
if (e->min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
min_heap_shift_up_(s, e->min_heap_idx, last);
else
min_heap_shift_down_(s, e->min_heap_idx, last);
e->min_heap_idx = -1;
return 0;
}
return -1;
}
首先进行删除操作,之后填补删除后的空位置,通过最后一个元素添加进行填补,如下:
- 要删除31号元素,需要将最后一个元素24号和31号元素的父亲比较,也就是25号元素
- 如果小于,按照完全二叉树的规则,小的元素要在上面,所以会从要删除元素的索引处开始向上寻找,依次和删除元素的父亲,爷爷,太爷爷等等,比较,当寻找到自己的位置时,会进行添加操作。
- 如果大于,按照完全二叉树的规则,大的元素在下面,所以会从要删除的元素的索引处开始向下寻找,注意,这里向下寻找是和要删除的元素的小儿子比较,何为小儿子,看下代码:
右儿子与左儿子比较,哪个儿子小,就赋值给min_child,所以,最后元素会依次和删除元素的小儿子,小孙子等等,比较,当寻找到自己的位置时,会进行添加操作。
unsigned min_child = 2 * (hole_index + 1); /* 要删除元素的右儿子 */
min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
这样就完成了删除操作。
/---------------------------------------------------------------------------------------------------------/
华丽的分割线
下面是我测试写出小demo:
#include <stdio.h>
struct event {
int value;
unsigned int min_heap_idx;
};
typedef struct min_heap
{
struct event** p; // 指向二叉堆根节点,堆成员为指向事件event的指针
unsigned n, a; /* 堆总大小,单位是个而不是字节 */
}min_heap_t;
void min_heap_ctor(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; }
void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
{
unsigned parent = (hole_index - 1) / 2; /* init:0 */
while(hole_index && min_heap_elem_greater(s->p[parent], e)) //s->[parent] > e
{
(s->p[hole_index] = s->p[parent])->min_heap_idx = hole_index;
hole_index = parent;
parent = (hole_index - 1) / 2;
}
(s->p[hole_index] = e)->min_heap_idx = hole_index;
}
int min_heap_elem_greater(struct event *a, struct event *b)
{
return (a->value > b->value);
}
int min_heap_reserve(min_heap_t* s, unsigned n)
{
if(s->a < n)
{
struct event** p;
unsigned a = s->a ? s->a * 2 : 8;
if(a < n) /* 第一次 */
a = n; /* 上来直接怼(申请)8个(event *)指针内存,s->p指向头 */
if(!(p = (struct event**)realloc(s->p, a * sizeof *p)))
return -1;
s->p = p;
s->a = a;
}
return 0;
}
int min_heap_push(min_heap_t* s, struct event* e)
{
if(min_heap_reserve(s, s->n + 1))
return -1;
min_heap_shift_up_(s, s->n++, e);
return 0;
}
void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
{
unsigned min_child = 2 * (hole_index + 1);
while(min_child <= s->n)
{
min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
if(!(min_heap_elem_greater(e, s->p[min_child])))
break;
(s->p[hole_index] = s->p[min_child])->min_heap_idx = hole_index;
hole_index = min_child;
min_child = 2 * (hole_index + 1);
}
min_heap_shift_up_(s, hole_index, e);
}
int min_heap_erase(min_heap_t* s, struct event* e)
{
if(((unsigned int)-1) != e->min_heap_idx)
{
struct event *last = s->p[--s->n];
unsigned parent = (e->min_heap_idx - 1) / 2;
/* we replace e with the last element in the heap. We might need to
* shift it upward if it is less than its parent, or downward if it is
* greater than one or both its children. Since the children are known
* to be less than the parent, it can't need to shift both up and
* down. */
if (e->min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
min_heap_shift_up_(s, e->min_heap_idx, last);
else
min_heap_shift_down_(s, e->min_heap_idx, last);
e->min_heap_idx = -1;
return 0;
}
return -1;
}
int main(void)
{
min_heap_t s;
min_heap_t *pheap = &s;
min_heap_ctor(pheap);
int values[11]= {25,16,26,19,24,65,13,31,68,32,20};
// int values[10]= {13,16,19,21,24,26,31,32,65,68};
int i = 0;
struct event * pev;
printf("insert all.\n");
for(;i< 11;++i)
{
pev = (struct event *)malloc(sizeof(struct event));
pev->value = values[i];
min_heap_push(pheap, pev);
pev = NULL;
}
i = 0;
while(pheap->p[i] != NULL)
{
printf("p[%d]->value=%d,min_idx=%d\n",i,(pheap->p[i])->value,(pheap->p[i])->min_heap_idx);
i++;
}
printf("num:%d\n",s.n);
#if 0
/* insert value:14 */
printf("insert value=14.\n");
pev = (struct event *)malloc(sizeof(struct event));
pev->value = 14;
min_heap_push(pheap, pev);
i = 0;
while(pheap->p[i] != NULL)
{
printf("p[%d]->value=%d,min_idx=%d\n",i,(pheap->p[i])->value,(pheap->p[i])->min_heap_idx);
i++;
}
printf("num:%d\n",s.n);
#endif
printf("delete value=31.\n");
pev = pheap->p[7];
min_heap_erase(pheap,pev);
i = 0;
while(pheap->p[i] != NULL)
{
printf("p[%d]->value=%d,min_idx=%d\n",i,(pheap->p[i])->value,(pheap->p[i])->min_heap_idx);
i++;
}
printf("num:%d\n",s.n);
while(1);
}