Skip to content
This repository has been archived by the owner on Sep 29, 2018. It is now read-only.

Commit

Permalink
Implement priorityStack
Browse files Browse the repository at this point in the history
First version, can be optimized further if needed.

A good and fast priorityQueue or priorityStack can be very
important for implementing a good A* algorithm.
  • Loading branch information
avdg committed Jun 3, 2015
1 parent 6015fa3 commit b57e458
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 0 deletions.
74 changes: 74 additions & 0 deletions scripts/_generics.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,83 @@ var parseCommand = function(command) {
return args;
};

var priorityStack = function(f, queue) {
if (f === undefined) {
f = function(a, b) {
if (a > b) return 1;
if (a < b) return -1;
return 0;
};
}

if (typeof f !== 'function') {
throw Error("Expected a function as first argument but got " + typeof f);
}

this.f = f;
this.queue = (queue || []).sort(this.f);
};

priorityStack.prototype = {
get length() {
return this.queue.length;
}
};

priorityStack.prototype.push = function(items) {
if (Array.isArray(items)) {
items = items.sort(this.f);
} else {
items = [items];
}

var newQueue = [];

// Merge sorted lists
var i = 0, j = 0;
while (i < this.queue.length && j < items.length) {
while(i < this.queue.length && this.f(this.queue[i], items[j]) <= 0) {
newQueue.push(this.queue[i]);
i++;
}

while(j < items.length && this.f(this.queue[i], items[j]) > 0) {
newQueue.push(items[j]);
j++;
}
}

// Merge remaining
if (i < this.queue.length) {
newQueue = newQueue.concat(this.queue.slice(i));
} else if (j < items.length) {
newQueue = newQueue.concat(items.slice(j));
}

this.queue = newQueue;
};

priorityStack.prototype.pop = function(f) {
return this.queue.pop();
};

priorityStack.prototype.peek = function(f) {
return this.queue[this.queue.length - 1];
};

priorityStack.prototype.modify = function(f) {
this.f = f;
this.queue = this.queue.sort(this.f);
};

priorityStack.prototype.toArray = function() {
return this.queue;
};

module.exports = {
bufferConsole: bufferConsole,
generator: generator,
getTimeDiff: getTimeDiff,
parseCommand: parseCommand,
priorityStack: priorityStack,
};
111 changes: 111 additions & 0 deletions test/scripts/generics.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,115 @@ describe("Scripts: _generics", function() {
);
});
});

describe('priorityStack', function() {
it('Must accept a function', function() {
var invalidPriorityStackArgument = function() {
new generics.priorityStack("blablablaah");
};
var check = function(e) {
return e instanceof Error &&
e.message === "Expected a function as first argument but got string";
};

assert.throws(invalidPriorityStackArgument, check);
});

it('Should use the default sorter when no function is given', function() {
var stack = new generics.priorityStack();
stack.push(4);
stack.push(5);
stack.push(3);

assert.deepEqual(stack.toArray(), [3, 4, 5]);
});

it('Should accept arrays second argument on construction', function() {
var stack = new generics.priorityStack(undefined, [4, 5, 3]);
assert.deepEqual(stack.toArray(), [3, 4, 5]);
});

it('Should accept arrays while pushing more items on the stack', function() {
var stack = new generics.priorityStack();
stack.push([4, 5, 3]);

assert.deepEqual(stack.toArray(), [3, 4, 5]);
});

it('Should be able to pop off the latest in the array', function() {
var stack = new generics.priorityStack(undefined, [4, 5, 3]);
assert.deepEqual(stack.pop(), 5);

assert.deepEqual(stack.toArray(), [3, 4]);
});

it('Should be able to provide the correct length', function() {
var stack = new generics.priorityStack();
assert.equal(0, stack.length);

stack.push(4);
assert.equal(1, stack.length);

stack.push(5);
assert.equal(2, stack.length);

stack.push(3);
assert.equal(3, stack.length);

stack.push(6);
assert.equal(4, stack.length);

assert.equal(stack.pop(), 6);
assert.equal(3, stack.length);

assert.deepEqual(stack.toArray(), [3, 4, 5]);
});

it('Should be able to peek', function() {
var stack = new generics.priorityStack();
assert.equal(undefined, stack.peek());

stack.push(4);
assert.equal(4, stack.peek());

stack.push(5);
assert.equal(5, stack.peek());

stack.push(3);
assert.equal(5, stack.peek());

stack.push(6);
assert.equal(6, stack.peek());

assert.equal(stack.pop(), 6);
assert.equal(5, stack.peek());

assert.deepEqual(stack.toArray(), [3, 4, 5]);
});

it('Should be able to be used by a custom compare function', function() {
var f = function(a, b) {
if (a > b) return -1;
if (a < b) return 1;
return 0;
};

var stack = new generics.priorityStack(f, [4, 3, 5]);
assert.deepEqual(stack.toArray(), [5, 4, 3]);
});

it('Should be able to modify itself with a new function', function() {
var f = function(a, b) {
if (a > b) return -1;
if (a < b) return 1;
return 0;
};

var stack = new generics.priorityStack(undefined, [4, 3, 5]);
assert.deepEqual(stack.toArray(), [3, 4, 5]);

stack.modify(f);
assert.deepEqual(stack.toArray(), [5, 4, 3]);
});
});
});

0 comments on commit b57e458

Please sign in to comment.