/* QuickSort Application of Scala Divide-and-Comquer Strategy Framework H. Conrad Cunningham Version #1: 30 March 2010 This is part of a Scala adaptation of the Java Quicksort application that uses the Strategy-based Divide-and-Conquer Framework described in the paper: H. C. Cunningham, Y. Liu, and C. Zhang. "Using Classic Problems to Teach Java Framework Design," _Science of Computer Programming_, Special Issue on Principles and Practice of Programming in Java (PPPJ 2004), Vol. 59, No. 1-2, pp. 147-169, January 2006. doi: 10.10.16/j.scico.2005.07.009. This Scala version uses generics to give more generality to the clients and to avoid casting. (The old Java version did not use generics.) 123456789012345678901234567890123456789012345678901234567890123456789012345678 */ /* The QuickSortStrategy class is a subclass of the Strategy-based Divide-and-Conquer Framework class DivConqStrategy, the base class for the Strategy objects used by the DivConqContext class. This class uses the QuickSortDesc class to represent both the Problem and Solution objects. The sort is carried out in-place within the array encapsulated in the QuickSortDesc object. */ class QuickSortStrategy[T <% Ordered[T]] extends DivConqStrategy[QuickSortDesc[T],QuickSortDesc[T]]{ // Stop when segment to sort is of length one def isSimple(p: QuickSortDesc[T]): Boolean = (p.getFirst >= p.getLast) // Nothing to do, so Problem description becomes Solution description. def simplySolve(p: QuickSortDesc[T]): QuickSortDesc[T] = p // Partition to elements < the pivot element and >= pivot element. def decompose (p: QuickSortDesc[T]) : Array[QuickSortDesc[T]] = { val first = p.getFirst val last = p.getLast val a = p.getArr val x = a(first) // pivot value var sp = first; for (i <- (first + 1) to last) { if (a(i) < x) { sp += 1 swap(a,sp,i) } } swap(a,first,sp) val ps = new Array[QuickSortDesc[T]](2) ps(0) = new QuickSortDesc[T](a,first,sp-1) ps(1) = new QuickSortDesc[T](a,sp+1,last) ps } // Array sorted in place, so Problem description becomes Solution. def combine(p: QuickSortDesc[T], ss: Seq[QuickSortDesc[T]]) : QuickSortDesc[T] = p private def swap (a: Array[T], first: Int, last: Int) { val temp = a(first) a(first) = a(last) a(last) = temp } } /* Singleton object QuickSortTest holds a simple testing script for the QuickSort application. */ object QuickSortStrategyTest { def main (args: Array[String]) { val st = new QuickSortStrategy[Int] val qs = new DivConqContext[QuickSortDesc[Int],QuickSortDesc[Int]](st) println("\nBeginning of QuickSortStrategy test.\n") val sort10 = Array(10, 9, 1, 2, 8, 7, 5, 5, 3, 4) println("Unsorted: " + seqAsStr(sort10)) qs.solve( new QuickSortDesc(sort10, 0, sort10.length-1) ) println("Sorted: " + seqAsStr(sort10)) println(); val sortrev = Array(9, 8, 7, 5, 5, 4, 3, 2, 1) println("Unsorted: " + seqAsStr(sortrev)) qs.solve( new QuickSortDesc(sortrev, 0, sortrev.length-1) ) println("Sorted: " + seqAsStr(sortrev)) println val sorted = Array(1, 2, 3, 4, 5, 5, 7, 8, 9) println("Unsorted: " + seqAsStr(sorted)) qs.solve( new QuickSortDesc(sorted, 0, sorted.length-1) ) println("Sorted: " + seqAsStr(sorted)) println val sort01 = Array(1) println("Unsorted: " + seqAsStr(sort01)) qs.solve( new QuickSortDesc(sort01, 0, sort01.length-1) ) println("Sorted: " + seqAsStr(sort01)) println val sort00 = new Array[Int](0) println("Unsorted: " + seqAsStr(sort00)) qs.solve( new QuickSortDesc(sort00, 0, sort00.length-1) ) println("Sorted: " + seqAsStr(sort00)) println println("End of QuickSortStrategy test.") } // Local method to aid in printing array private def seqAsStr[T](s: Seq[T]) = s.mkString("Array(",",",")") }