Skip to content

maintain legacy options for min and max queues #78

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
May 6, 2025
1 change: 1 addition & 0 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"comma-dangle": ["error", {
"functions": "ignore"
}],
"no-confusing-arrow": 0,
"no-underscore-dangle": [
"error",
{ "allowAfterThis": true }
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [6.3.3] - 2025-05-01

### Fixed
- Added backward compatibility with v5's compare function format for MinPriorityQueue and MaxPriorityQueue
- Fixed iterator type.

## [6.3.2] - 2025-01-05

### Fixed
Expand Down
15 changes: 14 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ A heap-based implementation of priority queue in javascript with typescript supp
<img src="https://user-images.githubusercontent.com/6517308/121813242-859a9700-cc6b-11eb-99c0-49e5bb63005b.jpg">


# Contents (v6)
# Contents
* [Install](#install)
* [require](#require)
* [import](#import)
Expand Down Expand Up @@ -123,6 +123,19 @@ const numbersQueue = new MinPriorityQueue();
const bidsQueue = new MaxPriorityQueue((bid) => bid.value);
```

##### Legacy Compare Function (v5 compatibility)
For backward compatibility with v5, you can also pass a compare function in an options object:

```js
// MinPriorityQueue with legacy compare
const minQueue = new MinPriorityQueue({ compare: (a, b) => a - b });

// MaxPriorityQueue with legacy compare
const maxQueue = new MaxPriorityQueue({ compare: (a, b) => a - b });
```

This format is supported for backward compatibility with v5 of the library.

### fromArray
If the queue is being created from an existing array, and there is no desire to use an extra O(n) space, this static function can turn an array into a priority queue in O(n) runtime.

Expand Down
3 changes: 2 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PriorityQueue } from './src/priorityQueue';
import { MinPriorityQueue } from './src/minPriorityQueue';
import { MinPriorityQueue, LegacyOptions } from './src/minPriorityQueue';
import { MaxPriorityQueue } from './src/maxPriorityQueue';
import { ICompare, IGetCompareValue } from '@datastructures-js/heap';

Expand All @@ -8,3 +8,4 @@ export { MinPriorityQueue }
export { MaxPriorityQueue }
export { ICompare }
export { IGetCompareValue }
export { LegacyOptions }
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@datastructures-js/priority-queue",
"version": "6.3.2",
"version": "6.3.3",
"description": "A heap-based implementation of priority queue in javascript with typescript support.",
"main": "index.js",
"types": "index.d.ts",
Expand Down
3 changes: 2 additions & 1 deletion src/maxPriorityQueue.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { MaxHeap, IGetCompareValue } from '@datastructures-js/heap';
import { LegacyOptions } from './minPriorityQueue';

export class MaxPriorityQueue<T> implements Iterable<T> {
constructor(getCompareValue?: IGetCompareValue<T>, heap?: MaxHeap<T>);
constructor(options?: IGetCompareValue<T> | LegacyOptions<T>, heap?: MaxHeap<T>);
[Symbol.iterator](): Iterator<T, any, undefined>;
size(): number;
isEmpty(): boolean;
Expand Down
18 changes: 13 additions & 5 deletions src/maxPriorityQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,22 @@ const getMaxCompare = (getCompareValue) => (a, b) => {

/**
* @class MaxPriorityQueue
* @extends MaxHeap
*/
class MaxPriorityQueue {
constructor(getCompareValue, _heap) {
if (getCompareValue && typeof getCompareValue !== 'function') {
throw new Error('MaxPriorityQueue constructor requires a callback for object values');
constructor(options, _heap) {
// Handle legacy options format ({ compare: fn })
if (options && typeof options === 'object' && typeof options.compare === 'function') {
this._getCompareValue = null;
const compareFunction = (a, b) => options.compare(a, b) >= 0 ? -1 : 1;
this._heap = _heap || new Heap(compareFunction);
} else {
// Current format (direct compare function)
const getCompareValue = options;
if (getCompareValue && typeof getCompareValue !== 'function') {
throw new Error('MaxPriorityQueue constructor requires a callback for object values');
}
this._heap = _heap || new MaxHeap(getCompareValue);
}
this._heap = _heap || new MaxHeap(getCompareValue);
}

/**
Expand Down
6 changes: 5 additions & 1 deletion src/minPriorityQueue.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { MinHeap, IGetCompareValue } from '@datastructures-js/heap';

export interface LegacyOptions<T> {
compare: (a: T, b: T) => number;
}

export class MinPriorityQueue<T> implements Iterable<T> {
constructor(getCompareValue?: IGetCompareValue<T>, heap?: MinHeap<T>);
constructor(options?: IGetCompareValue<T> | LegacyOptions<T>, heap?: MinHeap<T>);
[Symbol.iterator](): Iterator<T, any, undefined>;
size(): number;
isEmpty(): boolean;
Expand Down
17 changes: 13 additions & 4 deletions src/minPriorityQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,20 @@ const getMinCompare = (getCompareValue) => (a, b) => {
* @class MinPriorityQueue
*/
class MinPriorityQueue {
constructor(getCompareValue, _heap) {
if (getCompareValue && typeof getCompareValue !== 'function') {
throw new Error('MinPriorityQueue constructor requires a callback for object values');
constructor(options, _heap) {
// Handle legacy options format ({ compare: fn })
if (options && typeof options === 'object' && typeof options.compare === 'function') {
this._getCompareValue = null;
const compareFunction = (a, b) => options.compare(a, b) <= 0 ? -1 : 1;
this._heap = _heap || new Heap(compareFunction);
} else {
// Current format (direct compare function)
const getCompareValue = options;
if (getCompareValue && typeof getCompareValue !== 'function') {
throw new Error('MinPriorityQueue constructor requires a callback for object values');
}
this._heap = _heap || new MinHeap(getCompareValue);
}
this._heap = _heap || new MinHeap(getCompareValue);
}

/**
Expand Down
16 changes: 16 additions & 0 deletions test/maxPriorityQueue.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,4 +128,20 @@ describe('MaxPriorityQueue', () => {
});
});
});

describe('legacy compare function', () => {
const values = [50, 80, 30, 90, 60, 40, 20];
const maxQ = new MaxPriorityQueue({ compare: (a, b) => a - b });

it('enqueue and dequeue with legacy compare', () => {
values.forEach((value) => maxQ.enqueue(value));
expect(maxQ.dequeue()).to.equal(90);
expect(maxQ.dequeue()).to.equal(80);
expect(maxQ.dequeue()).to.equal(60);
expect(maxQ.dequeue()).to.equal(50);
expect(maxQ.dequeue()).to.equal(40);
expect(maxQ.dequeue()).to.equal(30);
expect(maxQ.dequeue()).to.equal(20);
});
});
});
16 changes: 16 additions & 0 deletions test/minPriorityQueue.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -125,4 +125,20 @@ describe('MinPriorityQueue', () => {
});

});

describe('legacy compare function', () => {
const values = [50, 80, 30, 90, 60, 40, 20];
const minQ = new MinPriorityQueue({ compare: (a, b) => a - b });

it('enqueue and dequeue with legacy compare', () => {
values.forEach((value) => minQ.enqueue(value));
expect(minQ.dequeue()).to.equal(20);
expect(minQ.dequeue()).to.equal(30);
expect(minQ.dequeue()).to.equal(40);
expect(minQ.dequeue()).to.equal(50);
expect(minQ.dequeue()).to.equal(60);
expect(minQ.dequeue()).to.equal(80);
expect(minQ.dequeue()).to.equal(90);
});
});
});