Richard Suchenwirth 2002-05-05 - Stacks and queues are containers for data objects with typical access methods:
In Tcl it is easiest to implement stacks and queues with lists, and the push method is most naturally just good old lappend, so we only have to code a single generic line for all stacks and queues:
interp alias {} push {} lappend
if 0 {It is pop operations in which stacks, queues, and priority queues differ:
Priority (a number) has to be assigned at pushing time - by pushing a list of two elements, the item itself and the priority, e.g..
push toDo [list "go shopping" 2] push toDo {"answer mail" 3} push toDo {"Tcl coding" 1} ;# most important thing to do
In a frequent parlage, priority 1 is the "highest", and the number increases for "lower" priorities - but you could push in an item with 0 for "ultrahigh" ;-) Popping a stack can be done like this:}
proc pop name { upvar 1 $name stack set res [lindex $stack end] set stack [lrange $stack 0 end-1] set res }
if 0 {Popping a queue is similarly structured, but with so different details that I found no convenient way to factor out things:}
proc qpop name { upvar 1 $name queue set res [lindex $queue 0] set queue [lrange $queue 1 end] set res }
if 0 {Popping a priority queue requires sorting out which item has highest priority. Sorting can be done when pushing, or when popping, and since our push is so nicely generic I prefer the second choice (as the number of pushs and pops should be about equal, it does not really matter). Tcl's lsort is stable, so items with equal priority will remain in the order in which they were queued:}
proc pqpop name { upvar 1 $name queue set queue [lsort -real -index 1 $queue] qpop queue ;# fall back to standard queue, now that it's sorted }
A practical application is e.g. in state space searching (see Searching A Star in Space), where the kind of container of the to-do list determines the strategy: