Skip to content

Commit e2bffe6

Browse files
committed
Initial commit
0 parents  commit e2bffe6

40 files changed

+2447
-0
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/node_modules/

Gruntfile.coffee

+71
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
module.exports = (grunt) ->
2+
grunt.initConfig
3+
coffee:
4+
compile:
5+
options:
6+
sourceMap: true
7+
expand: true
8+
flatten: false
9+
cwd: 'coffee'
10+
src: [ '**/*.coffee' ]
11+
dest: 'js/'
12+
ext: '.js'
13+
14+
test:
15+
expand: true
16+
flatten: false
17+
cwd: 'spec-coffee'
18+
src: [ '**/*.coffee' ]
19+
dest: 'spec/'
20+
ext: '.js'
21+
22+
requirejs:
23+
development:
24+
options:
25+
name: 'PriorityQueue'
26+
baseUrl: 'js/'
27+
optimize: 'none'
28+
out: './priority-queue.js'
29+
30+
minified:
31+
options:
32+
name: 'PriorityQueue'
33+
baseUrl: 'js/'
34+
optimize: 'uglify2'
35+
out: './priority-queue.min.js'
36+
37+
almond:
38+
options:
39+
name: 'index'
40+
baseUrl: 'js/'
41+
optimize: 'none'
42+
almond: true
43+
wrap: true
44+
out: './priority-queue.no-require.js'
45+
46+
almond_minified:
47+
options:
48+
name: 'index'
49+
baseUrl: 'js/'
50+
optimize: 'uglify2'
51+
almond: true
52+
wrap: true
53+
out: './priority-queue.no-require.min.js'
54+
55+
jasmine:
56+
all:
57+
src: 'js/**/*.js'
58+
options:
59+
specs: 'spec/**/*Spec.js'
60+
helpers: 'spec/**/*Helper.js'
61+
template: require('grunt-template-jasmine-requirejs')
62+
templateOptions:
63+
requireConfig:
64+
baseUrl: 'js/'
65+
66+
grunt.loadNpmTasks('grunt-contrib-coffee')
67+
grunt.loadNpmTasks('grunt-requirejs')
68+
grunt.loadNpmTasks('grunt-contrib-jasmine')
69+
70+
grunt.registerTask('default', [ 'coffee', 'requirejs' ])
71+
grunt.registerTask('test', [ 'coffee', 'jasmine' ])

LICENSE.md

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
License
2+
=======
3+
4+
I, Adam Hooper, the sole author of this project, waive all my rights to it and
5+
release it under the [Public
6+
Domain](http://creativecommons.org/publicdomain/zero/1.0/). Do with it what you
7+
will.

README.md

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
Priority Queue
2+
==============
3+
4+
A priority queue is a data structure with these operations:
5+
6+
| Operation | Syntax (js-priority-queue) | Description |
7+
| --------- | --- | ----------- |
8+
| Create | `var queue = new PriorityQueue();` | Creates a priority queue |
9+
| Queue | `queue.queue(value);` | Inserts a new value in the queue |
10+
| Length | `var length = queue.length;` | Returns the number of elements in the queue |
11+
| Peek | `var firstItem = queue.peek();` | Returns the smallest item in the queue and leaves the queue unchanged |
12+
| Dequeue | `var firstItem = queue.dequeue();` | Returns the smallest item in the queue and removes it from the queue |
13+
14+
You cannot access the data in any other way: you must dequeue or peek.
15+
16+
Why use this library? Two reasons:
17+
18+
1. It's easier to use than an Array, and it's clearer.
19+
2. It can make your code execute more quickly.
20+
21+
Installing
22+
==========
23+
24+
Download `priority-queue.js`. Alternatively, install through Bower:
25+
`bower install js-priority-queue`
26+
27+
Include it through [RequireJS](http://requirejs.org/).
28+
29+
Then write code like this:
30+
31+
require([ 'vendor/priority-queue' ], function(PriorityQueue) {
32+
var queue = new PriorityQueue({ comparator: function(a, b) { return b - a; });
33+
queue.queue(5);
34+
queue.queue(3);
35+
queue.queue(2);
36+
var lowest = queue.pop(); // returns 2
37+
});
38+
39+
If you don't like RequireJS, you can download the standalone version,
40+
`priority-queue.no-require.js`, and write:
41+
42+
var queue = new PriorityQueue({ comparator: function(a, b) { return b - a; });
43+
queue.queue(5);
44+
queue.queue(3);
45+
queue.queue(2);
46+
var lowest = queue.pop(); // returns 2
47+
48+
Options
49+
=======
50+
51+
How exactly will these elements be ordered? Let's use the `comparator` option.
52+
This is the argument we would pass to
53+
[Array.prototype.sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort):
54+
55+
var compareNumbers = function(a, b) { return a - b; };
56+
var queue = new PriorityQueue({ comparator: compareNumbers });
57+
58+
Strategies
59+
==========
60+
61+
We can implement this with a regular `Array`. We'll keep it sorted inversely,
62+
so `queue.dequeue()` maps to `array.pop()`.
63+
64+
But with an `Array`, we'll need to `splice()`, which can affect every single
65+
element in the array. An alternative is to create a
66+
[Binary Heap](http://en.wikipedia.org/wiki/Binary_heap), which writes far
67+
fewer array elements when queueing (though each element is written more slowly).
68+
69+
Finally, we can use a [B-Heap](http://en.wikipedia.org/wiki/B-heap). It's like a
70+
binary heap, except it orders elements such that during a single operation,
71+
writes occur closer to each other in memory. That can give a speed win.
72+
73+
Create the queues like this:
74+
75+
var queue = new PriorityQueue({ strategy: PriorityQueue.ArrayStrategy }); // Array
76+
var queue = new PriorityQueue({ strategy: PriorityQueue.BinaryHeapStrategy }); // simple binary heap
77+
var queue = new PriorityQueue({ strategy: PriorityQueue.BHeapStrategy }); // default
78+
79+
You'll see running times like this:
80+
81+
| Operation | Array | Binary heap | B-Heap |
82+
| --------- | ----- | ----------- | -------------- |
83+
| Create | O(1) | O(1) | O(1) |
84+
| Queue | O(n) (often slow) | O(lg n) (fast) | O(lg n) (fast) |
85+
| Peek | O(1) | O(1) | O(1) |
86+
| Dequeue | O(1) | O(lg n) | O(lg n) |
87+
88+
Contributing
89+
============
90+
91+
1. Fork this repository
92+
2. Run `npm install`
93+
3. Write the behavior you expect in `spec-coffee/`
94+
4. Edit files in `coffee/` until `grunt test` says you're done
95+
5. Run `grunt` to update `priority-queue.js` and `priority-queue.min.js`
96+
6. Submit a pull request
97+
98+
License
99+
=======
100+
101+
I, Adam Hooper, the sole author of this project, waive all my rights to it and
102+
release it under the [Public
103+
Domain](http://creativecommons.org/publicdomain/zero/1.0/). Do with it what you
104+
will.

bower.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "js-priority-queue",
3+
"version": "0.0.1",
4+
"main": "priority-queue.js",
5+
"ignore": [
6+
"**/.*",
7+
"node_modules",
8+
"coffee",
9+
"spec",
10+
"spec-coffee",
11+
"Gruntfile.js",
12+
"package.json"
13+
]
14+
}

coffee/PriorityQueue.coffee

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
define [
2+
'./priv/AbstractPriorityQueue'
3+
'./priv/ArrayStrategy'
4+
'./priv/BinaryHeapStrategy'
5+
'./priv/BHeapStrategy'
6+
], (
7+
AbstractPriorityQueue
8+
ArrayStrategy,
9+
BinaryHeapStrategy,
10+
BHeapStrategy
11+
) ->
12+
class PriorityQueue extends AbstractPriorityQueue
13+
constructor: (options) ->
14+
options ||= {}
15+
options.strategy ||= BinaryHeapStrategy
16+
options.comparator ||= (a, b) -> (a || 0) - (b || 0)
17+
super(options)
18+
19+
PriorityQueue.ArrayStrategy = ArrayStrategy
20+
PriorityQueue.BinaryHeapStrategy = BinaryHeapStrategy
21+
PriorityQueue.BHeapStrategy = BHeapStrategy
22+
23+
PriorityQueue

coffee/index.coffee

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# This library is defined in terms of AMD modules, but some people will want a
2+
# standalone version. This file, plus almond.js, provides that.
3+
#
4+
# If you're using an AMD loader, ignore this file.
5+
require [ './PriorityQueue' ], (PriorityQueue) -> window.PriorityQueue = PriorityQueue
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
define ->
2+
class AbstractPriorityQueue
3+
constructor: (options) ->
4+
throw 'Must pass options.strategy, a strategy' if !options?.strategy?
5+
throw 'Must pass options.comparator, a comparator' if !options?.comparator?
6+
@priv = new options.strategy(options)
7+
@length = 0
8+
9+
queue: (value) ->
10+
@length++
11+
@priv.queue(value)
12+
undefined
13+
14+
dequeue: (value) ->
15+
throw 'Empty queue' if !@length
16+
@length--
17+
@priv.dequeue()
18+
19+
peek: (value) ->
20+
throw 'Empty queue' if !@length
21+
@priv.peek()

coffee/priv/ArrayStrategy.coffee

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
define ->
2+
binarySearchForIndexReversed = (array, value, comparator) ->
3+
low = 0
4+
high = array.length
5+
while low < high
6+
mid = (low + high) >>> 1
7+
if comparator(array[mid], value) >= 0 # >=, instead of the usual <
8+
low = mid + 1
9+
else
10+
high = mid
11+
low
12+
13+
# Maintains a sorted Array. The running-time is bad in theory, but in
14+
# practice Array operations are small ... assuming there isn't much data.
15+
#
16+
# The Array is stored from last entry to first: we assume queue() will be
17+
# the same speed either way, but this way dequeue() is O(1) instead of O(n).
18+
class ArrayStrategy
19+
constructor: (@options) ->
20+
@comparator = @options.comparator
21+
@data = []
22+
23+
queue: (value) ->
24+
pos = binarySearchForIndexReversed(@data, value, @comparator)
25+
@data.splice(pos, 0, value)
26+
undefined
27+
28+
dequeue: ->
29+
@data.pop()
30+
31+
peek: ->
32+
@data[@data.length - 1]

0 commit comments

Comments
 (0)