[prev] [up] [next]

Sample Programs

The following code snipplets can be executed in a workspace, or alternatively be copied into a class (typically a class method).

Complexity

Care for an algorithms complexity; the following example demonstrates an algorithm with an exponential growth in CPU time.

The goal is to compute the number of different ways to change a dollar into an arbitrary number of 50, 25, 10, 5 and 1 cent coins.
(I.e. one solution would be: 50 + 25 + 10 + 5 + 5 + 1 + 1 + 1 + 1 + 1)

Version 1

The general algorithm is: A code for the above algorithm is straight forward:
    |f coins solutions|

    coins := #(50 25 10 5 1).

    f := [:coinsAlreadyTaken :amount|
	    |solutions t|

	    amount == 0 ifTrue:[
		Array with: coinsAlreadyTaken 
	    ] ifFalse:[
		solutions := Set new.
		coins do:[:cn | 
		    cn <= amount ifTrue:[
			solutions 
			    addAll:
				(f 
				    value:(coinsAlreadyTaken copy add:cn; yourself)
				    value:amount-cn)
		    ]
		].
		solutions
	    ]
	 ].

    solutions := f value:#() asBag value:100.
    solutions size
this algorithm works and returns the correct number of solutions (292);
however, be warned, it takes forever to compute it (try it overnight ;-).

Version 2

The obvious fix is to remember already computed changes in a cache (solutionForAmountAndCoins) and avoid recomputing them:
    |solutionForAmountAndCoins f coins solutions|

    coins := #(50 25 10 5 1).
    solutionForAmountAndCoins := Dictionary new.

    f := [:coinsAlready :amount|
	    |solutions t|

	    amount == 0 ifTrue:[
		{ coinsAlready }
	    ] ifFalse:[
		t := solutionForAmountAndCoins at:amount ifAbsentPut:[Dictionary new].
		solutions := t at:coinsAlready ifAbsent:nil.
		solutions isNil ifTrue:[
		    solutions := Set new.
		    coins do:[:cn | 
			cn <= amount ifTrue:[
			    solutions 
				addAll:
				    (f 
					value:(coinsAlready copy add:cn; yourself)
					value:amount-cn)
			]
		    ].
		    t at:coinsAlready put:solutions.
		].
		solutions
	    ]
	 ].

    solutions := f value:#() asBag value:100.
    solutions size

Version 3

Another solution (from SICP), using a slightly different algorithm is:
    |numberOfSolutions valOfCoin cc|

    valOfCoin := #(1 5 10 25 50).

    cc := [:amount :kinds |
	    amount == 0 
	      ifTrue:[ 1 ]
	      ifFalse:[
		amount < 0 
		  ifTrue:[ 0 ]
		  ifFalse:[
		    kinds == 0
		      ifTrue:[0]
		      ifFalse:[
			(cc value:amount value:(kinds - 1))
			+
			(cc value:(amount - (valOfCoin at:kinds))
			    value:kinds)
		      ]
		  ]
	      ]
	  ].

    numberOfSolutions := cc value:100 value:5.
    numberOfSolutions

Continue in "Smalltalk basics".


[stx-logo]
Copyright © Claus Gittinger Development & Consulting
Copyright © eXept Software AG

<cg@exept.de>

Doc $Revision: 1.2 $ $Date: 2003/04/25 20:01:26 $