diff --git a/README.textile b/README.textile index d147e99..ad00242 100644 --- a/README.textile +++ b/README.textile @@ -41,6 +41,14 @@ h3. queue.push(element, ...) Add new elements to the queue. Returns the new length. +h3. queue.pull(element) + +Pull any element instead of maximum priority out of the queue and return it. + +h3. queue.top() + +Peek the item with maximum priority from the queue and return its value. + h3. queue.shift() Remove the item with maximum priority from the queue and return it. diff --git a/package.json b/package.json index 99786f8..78139dc 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { "name": "priority_queue" -, "version": "0.1.3" +, "version": "0.1.4" , "description": "simple priority queue using a binary heap" , "main": "./priority_queue.js" , "scripts": diff --git a/priority_queue.js b/priority_queue.js index a54b844..bcce78c 100644 --- a/priority_queue.js +++ b/priority_queue.js @@ -25,7 +25,7 @@ exports.PriorityQueue = function PriorityQueue(compare, queue) { function remove(i) { var t = queue[i], b = queue.pop(); - if (queue.length > 0) { + if (queue.length > 0 && i < queue.length) { queue[i] = b; heapify(i); } @@ -44,6 +44,13 @@ exports.PriorityQueue = function PriorityQueue(compare, queue) { return queue.length; } + this.pull = function (v) { + var i = 0; + while (i < queue.length && queue[i] !== v) { i++; } + return (i === queue.length) ? undefined : remove(i); + } + + this.top = function top() { return queue[0]; } this.shift = function shift() { return remove(0); } this.__defineGetter__('length', function length() { return queue.length }); diff --git a/test/priority_queue_test.js b/test/priority_queue_test.js index dcd7a1a..ca89cc3 100644 --- a/test/priority_queue_test.js +++ b/test/priority_queue_test.js @@ -15,7 +15,10 @@ var suite = vows.describe('priority queue').addBatch( , 'with five items pushed': { topic: push(2, 1, 3, Math.PI, 0) , 'obeys the heap property': assertHeap - , 'has a length of five': hasLength(5) + , 'has a length of five': hasLength(5) + , 'has the minimum on the top': topReturns(0) + , 'has one valid item pulled': pullItem(3) + , 'has a length of four': hasLength(4) , 'returns its items in ascending order': assertOrdering(asc) , 'is empty': hasLength(0) , 'holds while pushing and shifting 1000 random values': pushAndShift(1000, asc, 0) @@ -31,6 +34,9 @@ var suite = vows.describe('priority queue').addBatch( { topic: push(2, 1, 3, Math.PI, 0) , 'obeys the heap property': assertHeap , 'has a length of five': hasLength(5) + , 'has the maxinum on the top': topReturns(Math.PI) + , 'has one invalid item pulled': pullItem(-1) + , 'has a length of four': hasLength(5) , 'returns its items in descending order': assertOrdering(desc) , 'is empty': hasLength(0) , 'holds while pushing and shifting 1000 random values': pushAndShift(1000, desc, 0) @@ -40,6 +46,9 @@ var suite = vows.describe('priority queue').addBatch( , 'A queue with initial data': { topic: makeQueue(pq.min_first, [1, 4, 2, 23, 0, -99]) , 'has a length of six': hasLength(6) + , 'has the mininum on the top': topReturns(-99) + , 'has one valid item pulled': pullItem(23) + , 'has a length of five': hasLength(5) , 'obeys the heap property': assertHeap , 'and five items pushed': { topic: push(2, 1, 3, Math.PI, 0) @@ -57,6 +66,11 @@ function hasLength(n) { assert.strictEqual(t.store.length, n) } } +function topReturns(v) { + return function(t) { + assert.deepEqual(t.queue.top(), v) + } +} function shiftReturns(v) { return function(t) { assert.deepEqual(t.queue.shift(), v) @@ -76,6 +90,13 @@ function push(/* element, ... */) { return function (t) { t.queue.push.apply(t.queue, elements); return t } } +function pullItem(v) { + return function(t) { + t.queue.pull(v); + assertHeap(t); + } +} + function makeQueue(compare, initital_data) { initital_data = initital_data || [] compare = compare || pq.min_first