###
Author: fachao zhang
File: collections.coffee
Released under the MIT license
Date : 2014-01-05
###
`
Object.prototype.hashCode = function(){
return -1;
};
Number.prototype.hashCode = function(){
if (!this.hash){
this.hash = this.valueOf();
}
return this.hash;
};
String.prototype.hashCode = function(){
if (!this.hash){
var off = 0, val = this, len = this.length, h = 0;
for (var i = 0; i < len; i++) {
h = 31*h + val.charCodeAt(off++);
}
this.hash = h;
}
return this.hash;
};
Boolean.prototype.hashCode = function(){
if (!this.hash){
this.hash = this.valueOf() ? 1231 : 1237;
}
return this.hash;
};
`
###Interface Iterator###
class Iterator
hasNext: ->
next : ->
remove : ->
###Interface###
class ListIterator extends Iterator
hasPrevious : ->
previous: ->
add : (obj) ->
set : (obj) ->
###Interface Collection###
class Collection
size : ->
isEmpty : ->
clear : ->
contains : (obj) ->
add : (obj) ->
remove: (obj) ->
iterator : ->
###Interface List###
class List extends Collection
get: (index) ->
set : (index , obj) ->
addAt :(index , obj) ->
removeAt : (index)->
indexOf : (obj) ->
###class ArrayList###
class ArrayList extends List
constructor : ->
@items = []
clear : ->
@items.splice 0, @size()
size : ->
return @items.length
isEmpty : ->
return @size() == 0
contains : (obj) ->
return (@indexOf obj) isnt -1
indexOf : (obj) ->
for item,i in @items
if obj is item
return i
return -1
_outOfBounds : (index) ->
return index < 0 || index >= @size()
get : (index) ->
if (@_outOfBounds index)
throw new Error "Index out of bounds."
return @items[index]
set : (index, obj) ->
if (@_outOfBounds index)
throw new Error "Index out of bounds."
old = @items[index]
@items[index] = obj
return old
add : (obj) ->
@items.push obj
return true;
addAt : (index, obj) ->
if (@_outOfBounds index)
throw new Error "Index out of bounds."
@items.splice index, 0, obj
return true
remove : (obj) ->
return @removeAt (@indexOf obj);
removeAt : (index) ->
if (@_outOfBounds index)
throw new Error "Index out of bounds."
@items.splice index, 1
return true
iterator : ->
return new ArrayListIterator this
toArray : ->
return @items
toString : ->
if(!JSON)
throw new Error "JSON object is not support in your browser, pleasse download and use json2.js."
return JSON.stringify @items
valueOf : ->
return @toString()
###class ArrayListIterator###
class ArrayListIterator extends Iterator
constructor : (list) ->
@current = 0
@list = list
hasNext : ->
return @current < @list.size()
next : ->
if !@hasNext()
throw new Error "No such element error."
return @list.get @current++
remove : ->
@list.removeAt --@current
###class Node###
class Node
constructor : (@data, @prev, @next)->
###class LinkedList###
class LinkedList extends List
constructor : ->
@clear()
size : ->
return @len;
isEmpty : ->
return @size() is 0
clear : ->
@head = new Node null, null, null
@tail = new Node null, null, null
@tail.prev = @head
@head.next = @tail
@len = 0
@count = 0
@count++
contains : (obj) ->
return (@indexOf obj) isnt -1
add : (obj) ->
@addAt @size(), obj
return true
remove : (obj) ->
`
for(var current = this.head.next; current !== this.tail; current = current.next){
if(current.data === obj){
this._remove(current);
return true;
}
}
`
return false
_remove: (node) ->
node.next.prev = node.prev;
node.prev.next = node.next;
oldData = node.data
node = null
@len--
@count++
return oldData
get: (index) ->
return @_getNode(index).data
set : (index , obj) ->
node = @_getNode(index)
oldVal = node.data
node.data = obj
return oldVal
addAt :(index , obj) ->
@_addBefore @_getNode(index), obj
removeAt : (index)->
return @_remove @_getNode(index)
indexOf : (obj) ->
index = 0
iter = @iterator()
while iter.hasNext()
if iter.next() == obj
return index
index++
return -1
_addBefore : (node, data) ->
newNode = new Node data, node.prev, node
newNode.prev.next = newNode
node.prev = newNode
@len++
@count++
_getNode : (index) ->
i = 0
p = new Node null, null, null;
if index<0 || index > @size()
throw new Error "Index out of bounds."
if index < (@size()/2)
p = @head.next;
`
for(i = 0; i < index; i++){
p = p.next;
}
`
else
p = @tail
`
for (i = this.size(); i > index; i--){
p = p.prev;
}
`
return p
iterator : ->
return new LinkedListIterator this
toArray : ->
result = []
iter = @iterator()
while iter.hasNext()
result.push iter.next()
return result
toString : ->
if(!JSON)
throw new Error "JSON object is not support in your browser, pleasse download and use json2.js."
result = @toArray()
return JSON.stringify result
valueOf : ->
return @toString()
###class LinkedListIterator###
class LinkedListIterator extends Iterator
constructor : (list) ->
@current = list.head.next
@expectedCount = list.count
@list = list
@okToRemove = false
hasNext : ->
return @current != @list.tail
next : ->
if @list.count != @expectedCount
throw new Error "Concurrent modification error."
if !@hasNext()
throw new Error "No such element error."
nextItem = @current.data
@current = @current.next
@okToRemove = true
return nextItem
remove : ->
if @list.count isnt @expectedCount
throw new Error "Concurrent modification error."
if !@okToRemove
throw new Error "Illegal state error."
@list.remove @current.prev
@okToRemove = false
@expectedCount++
###
@descripton : The Stack class represents a last-in-first-out (LIFO) stack of objects.
@extends : ArrayList
@methed : push, pop, peek
###
class Stack extends ArrayList
###
@descripton : Pushes an item onto the top of this stack.
@param obj : Any type.
@return : boolean -- It is true if add successed, else false.
###
push : (obj) ->
@add obj
###
@descripton : Removes the object at the top of this stack and returns that
object as the value of this function.
@return : obj -- the object at the top of this stack.
###
pop : ->
lastIndex = @size() - 1
top = @get lastIndex
@removeAt lastIndex
return top
###
@descripton : Looks at the object at the top of this stack without removing it
from the stack.
@return : obj -- the object at the top of this stack.
###
peek : ->
return @get @size() - 1
###
@descripton : The Stack class represents a last-in-first-out (LIFO) stack of objects.
@extends : LinkedList
@methed : push, pop, peek
###
class LinkedStack extends LinkedList
###
@descripton : Pushes an item onto the top of this stack.
@param obj : Any type.
@return : boolean -- It is true if add successed, else false.
###
push : (obj) ->
@add obj
###
@descripton : Removes the object at the top of this stack and returns that
object as the value of this function.
@return : obj -- the object at the top of this stack.
###
pop : ->
lastIndex = @size() - 1
top = @get lastIndex
@removeAt lastIndex
return top
###
@descripton : Looks at the object at the top of this stack without removing it
from the stack.
@return : obj -- the object at the top of this stack.
###
peek : ->
return @get @size() - 1
###
@descripton : The Queue class represents a FIFO (first-in-first-out) queue of objects.
@extends : ArrayList
@methed : enqueue, dequeue, peek
###
class Queue extends ArrayList
###
@descripton : Inserts the specified element into this queue
@param obj : Any type.
@return : boolean -- It is true if add successed, else false.
###
enqueue : (obj) ->
@add obj
###
@descripton : Retrieves and removes the head of this queue.
@return : obj -- the object at the top of this queue.
###
dequeue : ()->
top = @peek()
@removeAt 0
return top
###
@descripton : Retrieves, but does not remove, the head of this queue.
@return : obj -- the object at the top of this queue.
###
peek : ->
return @get 0
###
@descripton : The Queue class represents a FIFO (first-in-first-out) queue of objects.
@extends : LinkedList
@methed : enqueue, dequeue, peek
###
class LinkedQueue extends LinkedList
###
@descripton : Inserts the specified element into this queue
@param obj : Any type.
@return : boolean -- It is true if add successed, else false.
###
enqueue : (obj) ->
@add obj
###
@descripton : Retrieves and removes the head of this queue.
@return : obj -- the object at the top of this queue.
###
dequeue : ()->
top = @peek()
@removeAt 0
return top
###
@descripton : Retrieves, but does not remove, the head of this queue.
@return : obj -- the object at the top of this queue.
###
peek : ->
return @get 0