libevent中的小根堆(二)

上次说到向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;
}

首先进行删除操作,之后填补删除后的空位置,通过最后一个元素添加进行填补,如下:

  1. 要删除31号元素,需要将最后一个元素24号和31号元素的父亲比较,也就是25号元素
  2. 如果小于,按照完全二叉树的规则,小的元素要在上面,所以会从要删除元素的索引处开始向上寻找,依次和删除元素的父亲,爷爷,太爷爷等等,比较,当寻找到自己的位置时,会进行添加操作。
  3. 如果大于,按照完全二叉树的规则,大的元素在下面,所以会从要删除的元素的索引处开始向下寻找,注意,这里向下寻找是和要删除的元素的小儿子比较,何为小儿子,看下代码:
    右儿子与左儿子比较,哪个儿子小,就赋值给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);	
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值