文章标题

来源:互联网 发布:林忆莲 都市触觉 知乎 编辑:程序博客网 时间:2024/06/10 03:49

基于二项队列的优先队列


  • 基于二项队列的优先队列
      • 相关术语
      • 操作
      • 复杂度

相关术语

定义1
左有序的堆:每个节点的关键字大于或等于该节点左子树(如果子树存在)中
的所有关键字。

定义2
2次幂堆:根的右子树为空的左有序堆。也称二项树

定义3
二项队列:是2次幂堆的一个集合。其中不存在相等大小的堆。二项队列的结构
由那个队列的数目来决定的。对应于整数的二进制表示。

把二次幂堆表示为含有关键字的和两个指针的节点:
struct PQnode {Item key; PQlink l, r;}
把二项队列表示为二次幂堆的数组:
struct pq {PQlink *bq;}

操作

连接两个大小相等的2次幂堆
即具有最大关键字的根节点成为结果堆的根节点,另一个根节点作为结果堆的左子
节点,最大关键字的左子树作为另一个根节点的右子树。

PQlink pair(PQlink p, PQlink q) {    if (less(p->key, q->key)){        p->r = q->l;        q->l = p;        return q;    } else {        q->r = p->l;        p->l = q;        return p;    }}

二项队列的插入操作:
向二项队列插入一个元素的过程和二进制增加1完全一样。

#define z NULLPQlink PQinsert(PQ pq, Item v) {    int i;    PQlink c;    c = malloc(sizeof *t);    c->l = c->r = z;    c->key = v;    for (i = 0; i < maxBQsize; i++) {        if (c == z) {            break;        }        if (pq->bq[i] == z) {            pq->bq[i] = c;            break;        }        c = pair(c, pq->bq[i]);        pq->bq[i] = z;    }}

二项队列中删除最大元素的操作:
1. 扫描根节点找出最大元素,并从二项队列中删除包含最大元素的二次幂堆。
2. 从它的二次幂堆中删除根节点,并暂时构建一个包含二次幂堆其余部分的
二项队列。
3. 最后,使用join操作把这个二项队列合并为原来的二项队列。

Item PQdelmax(PQ pq) {    int i, max;     PQlink x;    Item v;    PQlink temp[maxBQsize];    for (i = 0, max = -1; i < maxBQsize; i++) {        if (pq->bq[i] != z) {            if ((max == -1) || less(v, pq->bq[i]->key) {                max = i;                v = pq->bq[i]->key;            }        }    }    x = pq->bq[max]->l;    for (i = max; i < maxBQsize; i++) {        temp[i] = z;    }    for (i = max; i > 0; i--) {        temp[i - 1] = x;        x = x->r;         temp[i - 1]->r = z;    }    free(pq->bq[max]);    pq->bq[max] = z;    BQjoin(pq->bq, temp);    return v;}

连接两个二项队列:
这个代码模仿了两个二进制数相加的过程

#define test(C, B, A) 4 * (C) + 2 * (B) + 1 * (A)void BQjoin(PQlink *a, PQlink *b) {    int i;    PQlink c = z;    for (i = 0; i < maxBQsize; i++) {        switch(test(c != z, b[i] != z, a[i] != z)) {            case 2:                a[i] = b[i];                break;            case 3:                c = pair(a[i], b[i]);                a[i] = z;                break;            case 4:                a[i] = c;                c = z;                break;            case 5:                c = pair(c, a[i]);                a[i] = z;                break;            case 6:            case 7:                c = pair(b, b[i]);                break;                }    }}void PQjoin(PQ a, PQ b) {    BQjoin(a->bq, b->bq);}

复杂度

优先队列ADT上的所有操作可用二项队列实现。在N个数据项的队列上执行的
任何操作需要O(lgN)来完成。

0 0
原创粉丝点击