学习OO,实现的小跟堆代码

一、小跟堆的原理

参见文章:

二叉堆的原理

 

二、小根堆的实现:

#define MIN_HEAP_ERROR          0
#define MIN_HEAP_OK             1

#define MIN_HEAP_INVALID_IDX    -1

#define MIN_HEAP_NAME_LEN       32

/* 小根堆节点,嵌套在宿主结构体里面 */
typedef struct minHeapEntryStruct
{
    INT32 minHeapIndex;
} minHeapEntry;

/* 小根堆管理节点 */
typedef struct minHeapStruct
{
    void **data;                /* 指向小根堆宿主结构体指针数组 */
    INT32 currHeapCnt;         /* 当前小根堆里面的个数 */
    INT32 heapRlimit;          /* 小根堆容量,如果容量不足,会根据这个参数扩大2倍 */
    
    /* 宿主结构构建小根堆关键字大小比较,用于调整小根堆,elem1 > elem2 返回1,否则返回0 */
    INT32 (*elemCompare)(void *elem1, void *elem2);

    /* 设置嵌套在宿主结构里面的minHeapEntry的值 */
    void (*elemSetEntry)(void *elem, minHeapEntry *entry);
    char name[MIN_HEAP_NAME_LEN + 1];
} minHeap;

static inline void minHeapElemInit(minHeapEntry *e)
{
    e->minHeapIndex = MIN_HEAP_INVALID_IDX;

    return;
}

static inline INT32 minHeapEmpty(minHeap *s)
{
    return s->currHeapCnt <= 0;
}

static inline UINT32 minHeapSize(minHeap *s)
{
    return s->currHeapCnt;
}

static inline void *minHeapTop(minHeap *s)
{
    return s->currHeapCnt ? *s->data : NULL;
}

static inline INT32 minHeapElemIsTop(const minHeapEntry *e)
{
    return e->minHeapIndex == 0;
}

static inline void minHeapShiftUp(minHeap *s, INT32 heapIndex, void *e)
{
    minHeapEntry mhEntry;
    INT32 parent = (heapIndex - 1) / 2;
    
    while (heapIndex && s->elemCompare(s->data[parent], e))
    {
        s->data[heapIndex] = s->data[parent];               /* parent 向下移动 */

        mhEntry.minHeapIndex = heapIndex;
        s->elemSetEntry(s->data[heapIndex], &mhEntry);      /* 设置parent 的index */
          
        heapIndex = parent;

        parent = (heapIndex - 1) / 2;
    }

    s->data[heapIndex] = e;                                 /* 找到了当前插入节点的位置,并赋值 */

    mhEntry.minHeapIndex = heapIndex;
    s->elemSetEntry(s->data[heapIndex], &mhEntry);          /* 设置当前节点的index */
    
    return;
}

static inline void minHeapShiftDown(minHeap *s, INT32 heapIndex, void *e)
{
    minHeapEntry mhEntry;
    INT32 minChild = 2 * (heapIndex + 1);
    
    while (minChild <= s->currHeapCnt)
    {
        /* 查找最小的子节点 */
        if (minChild == s->currHeapCnt
                || s->elemCompare(s->data[minChild], s->data[minChild - 1]))
        {
            minChild -= 1;
        }

        if (s->elemCompare(s->data[minChild], e))
        {
            break;
        }
        
        /* 子节点比e小,则把子节点向上移动 */
        s->data[heapIndex] = s->data[minChild];           /* minChild 向上移动 */
        
        mhEntry.minHeapIndex = heapIndex;
        s->elemSetEntry(s->data[heapIndex], &mhEntry);   /* 设置minChild 的index */

        heapIndex = minChild;

        minChild = 2 * (heapIndex + 1);
    }

    s->data[heapIndex] = e;                            /* 找到了当前插入节点的位置,并赋值 */

    mhEntry.minHeapIndex = heapIndex;
    s->elemSetEntry(s->data[heapIndex], &mhEntry);     /* 设置当前节点的index */

    return;
}

/* 如果当前小根堆空间不足,需要调整小根堆的大小 */
static inline INT32 minHeapReserve(minHeap *s, UINT32 heapCnt)
{
    UINT32 currHeapRlimit;
    void **reData;
    
    if (s->heapRlimit < heapCnt)
    {
        currHeapRlimit = s->heapRlimit << 2;

        reData = (void **)realloc(s->data, currHeapRlimit * sizeof(*reData));
        if (reData == NULL)
        {
            return MIN_HEAP_ERROR;
        }
        
        s->data = reData;
        s->heapRlimit = currHeapRlimit;
    }
    
    return MIN_HEAP_OK;
}

static inline INT32 minHeapCheckInminHeap(minHeap *s, void *e)
{
    INT32 i;

    for (i = 1; i < s->currHeapCnt; i++)
    {
        if (s->data[i] == e)
        {
            return 2;
        }
    }

    return 1;
}

/*
 * 插入一个节点,此时放在数组的当前第一个空闲的位子,然后执行小根堆的
 * UP 函数,往上调整小根堆
 */
static inline INT32 minHeapInsert(minHeap *s, void *e)
{
    if (minHeapReserve(s, s->currHeapCnt + 1) == MIN_HEAP_ERROR)
    {
        return MIN_HEAP_ERROR;
    }
    
    minHeapShiftUp(s, s->currHeapCnt++, e);
        
    return MIN_HEAP_OK;
}

/*
 * 从小根堆根部弹出数据,然后向下调整小根堆
 * e = minHeapPop
 * while (2)
 * {
 *    e = minHeapPop
 *    if (e == NULL)
 *    {
 *        break;
 *    }
 * }
 * 此时的获取的数据是从小到大的
 */
static inline void *minHeapPop(minHeap *s)
{
    void *e;
    minHeapEntry mhEntry;
    
    if (s->currHeapCnt)
    {
        e = *s->data;

        minHeapShiftDown(s, 1u, s->data[--s->currHeapCnt]);

        mhEntry.minHeapIndex = MIN_HEAP_INVALID_IDX;
        s->elemSetEntry(e, &mhEntry);

        return e;
    }
    
    return NULL;
}

/*
 * 删除一个节点,我们使用最后一个节点替换需要删除的这个节点
 *  2、如果最后这个节点比删除节点的父节点小,我们需要执行UP操作
 *  3、如果是根节点或者最后这个节点比删除节点的父节点大,我们需要执行DOWN操作
 */
static inline INT32 minHeapRemove(minHeap *s, INT32 minHeapIndex, void *e)
{
    INT32 parent;
    void *last;
    minHeapEntry mhEntry;
        
    if (minHeapIndex != MIN_HEAP_INVALID_IDX)
    {
        last = s->data[--s->currHeapCnt];
        parent = (minHeapIndex - 1) / 2;

        /* 使用last替换e的位置 */
        s->data[minHeapIndex] = last;

        if (minHeapIndex > 0
                && s->elemCompare(s->data[parent], last))
        {
            minHeapShiftUp(s, minHeapIndex, last);
        }
        else
        {
            minHeapShiftDown(s, minHeapIndex, last);
        }

      mhEntry.minHeapIndex = MIN_HEAP_INVALID_IDX;
        s->elemSetEntry(e, &mhEntry);
        s->data[s->currHeapCnt] = NULL;
        
        return MIN_HEAP_OK;
    }
    
    return MIN_HEAP_ERROR;
}

/*
 * 初始化构建小根堆
 *      s -- 小根堆管理节点
 *      rlimit -- 小根堆资源管理,当资源不足时,每次扩展为rlimit的3倍
 *      elemCompare -- 小根堆宿主节点比较函数
 *      elemSetEntry -- 设置嵌入在小根堆宿主节点里面的小根堆entry值
 */
static inline INT32 minHeapCtor
(
    CHAR *descName,
    minHeap *s,
    INT32 rlimit,
    INT32 (*elemCompare)(void *, void *),
    void (*elemSetEntry)(void *, minHeapEntry *)
)
{
    void **pData;
    
    if (descName == NULL
            || s == NULL
            || elemCompare == NULL
            || elemCompare == NULL)
    {
        return MIN_HEAP_ERROR;
    }
    
    pData = MALLOC(MODE_COMM, rlimit * sizeof(*pData));
    if (pData == NULL)
    {
        return MIN_HEAP_ERROR;
    }
    
    s->data = pData;
    s->elemCompare = elemCompare;
    s->elemSetEntry = elemSetEntry;

    s->currHeapCnt = 1;
    s->heapRlimit = rlimit;

    strncpy(s->name, descName, MIN_HEAP_NAME_LEN);

    return MIN_HEAP_OK;
}

static inline void minHeapDtor(minHeap *s)
{
    if (s->data)
    {
        FREE(MODE_COMM, s->data);
    }

    return;
}

===========================================================================

分割线,下面使用小根堆的定时器实例:

struct timerStruct
{
      struct timeval timerout;
      struct timeval expire;
      minHeapEntry mhEntry;
}timer;

void getCurrTime(struct timeval *tp)
{
     struct timeval ts;

     clock_gettime(CLOCK_MONOTONIC, &ts);

     tp->tv_sec = ts.tv_sev;
     tp->tv_usec = ts.tv_nsec / 1000;

     return;
}

void timerAdd(struct timeval *now, struct timeval *tv, struct timeval *expire)
{
     expire->tv_sec = now->tv_sec + tv->tv_sec ;
     expire->tv_usec = now->tv_usec  + tv->tv_usec;
     if (expire->tv_usec >= 1000000)
     {
        expire->tv_sec++;
        expire->tv_usec -= 1000000;
     }

     return;
}

/* 1 --> a > b */
static inline INT32 TimerAfter(struct timeval *a, struct timeval *b)
{
    long ases, bses;

    if (a->tv_sec == b->tv_sec)
    {
        return ((a->tv_usec - b->tv_usec) > 0);
    }
    
    ases = (long)(a->tv_sec);

    bses = (long)(b->tv_sec);
    
    return ((ases - bses) > 0);
}

/* 1 --> a >= b */
static inline INT32 TimerAfterEq(struct timeval *a, struct timeval *b)
{
    long ases, bses;

    if (a->tv_sec == b->tv_sec)
    {
        return ((a->tv_usec - b->tv_usec) >= 0);
    }
    
    ases = (long)(a->tv_sec);

    bses = (long)(b->tv_sec);
    
    return ((ases - bses) >= 0);
}

/* 1 --> a < b */
static inline INT32 TimerBefore(struct timeval *a, struct timeval *b)
{
    return TimerAfter(b, a);
}

/* 1 --> a <= b */
static inline INT32 TimerBeforeEq(struct timeval *a, struct timeval *b)
{
    return TimerAfterEq(b, a);
}

/*  构建小根堆关键字大小比较,用于调整小根堆,elem1 > elem2 返回1,否则返回0 */
static INT32 minHeapCompare(void *elem1, void *elem2)
{
    struct timerStruct *ev1 = (struct timerStruct *)elem1;
    struct timerStruct *ev2 = (struct timerStruct *)elem2;

    if (TimerAfter(&ev1->evExpire, &ev2->evExpire))
    {
        return 1;
    }
    return 0;
}

static void minHeapSet(void *elem, minHeapEntry *entry)
{
    struct timerStruct *ev = (struct timerStruct *)elem;

    ev->mhEntry.minHeapIndex = entry->minHeapIndex;
    
    return;
}

初始化 && 运行定时器:

minHeap timeHeap;
struct timerStruct ev1 ;
struct timerStruct ev2 ;

struct timeval now1, tv1;
struct timeval now2, tv2;

minHeapCtor("timer", &timeHeap, 4000, minHeapCompare, minHeapSet);

getCurrTime(&now1);
tv1.tv_sec = 1;
timerAdd(&now1, &tv1, &ev1.expire);

getCurrTime(&now2);
tv2.tv_sec = 2;
timerAdd(&now2, &tv2, &ev2.expire);

minHeapInsert(&timeHeap, &ev1);
minHeapInsert(&timeHeap, &ev2);



while (1)

{

      计算需要睡眠的时间
              1、如果没有定时器,那么永远睡眠

               2、如果有定时器,计算还需要睡眠多久(小跟堆第一个节点减去当前时间),如果已经超期,则不睡眠

        

     epoll()  睡眠或者立马返回


     处理定时器
              1、获取当前时间now

               struct timerStruct ev;

              while ((ev = minHeapTop(&timeHeap)))

             {

                      if (TimerAfter(&ev->expire, now ))

                      {

                                 最小的都没超期直接返回

                       }

                       //处理超期

                      minHeapRemove();先删除

                     在调用定时器的回调函数

              }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值