aureooms/js-d-ary-heap

View on GitHub
src/adt/DAryHeap.js

Summary

Maintainability
B
6 hrs
Test Coverage
A
100%
import merge from '../core/merge.js';
import pop from '../core/pop.js';
import push from '../core/push.js';
import remove from '../core/remove.js';
import siftdown from '../core/siftdown.js';
import siftup from '../core/siftup.js';

export default function DAryHeap(arity, compare) {
    // Arity of this heap

    this.arity = arity;

    // The comparison function

    this.compare = function (a, b) {
        return compare(a.value, b.value);
    };

    // The original comparison function

    this._compare = compare;

    // Array used to store values

    this.array = [];

    // Size of the heap

    this.length = 0;
}

DAryHeap.Reference = function (index, value) {
    this.index = index;
    this.value = value;
};

DAryHeap.prototype.swap = function (a, i, j) {
    const tmp = a[i];
    a[i] = a[j];
    a[j] = tmp;

    a[i].index = i;
    a[j].index = j;
};

DAryHeap.prototype.head = function () {
    if (this.length === 0) {
        return undefined;
    }

    return this.array[0].value;
};

DAryHeap.prototype.headreference = function () {
    if (this.length === 0) {
        return null;
    }

    return this.array[0];
};

DAryHeap.prototype.pop = function () {
    if (this.length === 0) {
        return undefined;
    }

    const a = this.array;
    const i = 0;
    const j = a.length;

    const reference = pop(this.arity, this.compare, this.swap, a, i, j);

    a.pop();

    --this.length;

    return reference.value;
};

DAryHeap.prototype.popreference = function () {
    if (this.length === 0) {
        return null;
    }

    const a = this.array;
    const i = 0;
    const j = a.length;

    const reference = pop(this.arity, this.compare, this.swap, a, i, j);

    a.pop();

    --this.length;

    return reference;
};

DAryHeap.prototype.push = function (value) {
    const a = this.array;
    const i = 0;
    const j = a.length;

    const reference = new DAryHeap.Reference(j, value);

    a.push(reference);

    push(this.arity, this.compare, this.swap, a, i, j);

    ++this.length;

    return reference;
};

DAryHeap.prototype.pushreference = function (reference) {
    const a = this.array;
    const i = 0;
    const j = a.length;

    reference.index = j;
    a.push(reference);

    push(this.arity, this.compare, this.swap, a, i, j);

    ++this.length;
};

DAryHeap.prototype.merge = function (other) {
    const a = this.array;
    const i = 0;
    const j = a.length;

    // Concat arrays of both heaps

    const b = a.concat(other.array);
    this.array = b;

    const k = b.length;

    // Update index of concatenated elements

    for (let t = j; t < k; ++t) {
        b[t].index = t;
    }

    merge(this.arity, this.compare, this.swap, b, i, j, k);

    this.length += other.length;
};

DAryHeap.prototype.update = function (reference, value) {
    const d = this._compare(value, reference.value);

    if (d < 0) {
        this.decreasekey(reference, value);
    } else if (d > 0) {
        this.increasekey(reference, value);
    } else {
        // D === 0 does not imply reference.value === value

        reference.value = value;
    }
};

DAryHeap.prototype.decreasekey = function (reference, value) {
    const a = this.array;
    const i = 0;
    const j = a.length;
    const k = reference.index;

    reference.value = value;

    siftup(this.arity, this.compare, this.swap, a, i, j, k);
};

DAryHeap.prototype.increasekey = function (reference, value) {
    const a = this.array;
    const i = 0;
    const j = a.length;
    const k = reference.index;

    reference.value = value;

    siftdown(this.arity, this.compare, this.swap, a, i, j, k);
};

DAryHeap.prototype.delete = function (reference) {
    const a = this.array;
    const i = 0;
    const j = a.length;
    const k = reference.index;

    remove(this.arity, this.compare, this.swap, a, i, j, k);

    a.pop();

    --this.length;
};