4
\$\begingroup\$

Trying to implement Heap Sort in Scala

class HeapSort
{
 private def swap(array: Array[Int], lhs: Int, rhs: Int) =
 {
 val tmp = array(lhs);
 array(lhs) = array(rhs);
 array(rhs) = tmp;
 }
 private def getParent(child: Int): Int = (child - 1) / 2;
 private def getChildren(parent: Int): Tuple2[Int, Int] =
 {
 val base = parent * 2;
 return (base + 1, base + 2);
 }
 private def swapLargestValue(array: Array[Int], setRoot: (Int) => Unit, root: Int, left: Int, right: Int): Boolean =
 {
 if (array(root) >= array(left) && array(root) >= array(right)) {
 return true;
 }
 if (array(left) >= array(right)) {
 swap(array, root, left);
 setRoot(left);
 }
 else {
 swap(array, root, right);
 setRoot(right);
 }
 return false;
 }
 private def siftDown(array: Array[Int], begin: Int, end: Int): Unit =
 {
 var root = begin;
 var (left, right) = getChildren(root);
 while(left < end) {
 if (swapLargestValue(array, root = _, root, left, if (right < end) right else left)) {
 return;
 }
 val x = getChildren(root);
 left = x._1;
 right = x._2;
 }
 }
 private def heapify(array: Array[Int], end: Int): Unit =
 {
 if (end == 0) {
 return;
 }
 var start = getParent(end - 1);
 while(start >= 0) {
 siftDown(array, start, end);
 start -= 1;
 }
 }
 def heapSort(array: Array[Int]): Unit =
 {
 if (array.length <= 1) {
 return;
 }
 heapify(array, array.length);
 var end = array.length - 1;
 while(end != 0) {
 swap(array, 0, end);
 siftDown(array, 0, end);
 end -= 1;
 }
 }
}
object HS {
 def main(args: Array[String]) {
 var data = Array(5,6,7,2,3,4,8,9,1,4,6,2,8,5,4,3);
 var hs = new HeapSort;
 hs.heapSort(data);
 println(data.deep.mkString(", "))
 }
}
asked Feb 1, 2017 at 7:53
\$\endgroup\$
1
  • 1
    \$\begingroup\$ @Heslacher: No. It was supposed to be siftDown(). It seems to be the standard name for that operation: stackoverflow.com/questions/34329942/… \$\endgroup\$ Commented Feb 1, 2017 at 8:31

1 Answer 1

1
\$\begingroup\$

Here is How the algorithm works with my sample code. Push all elements onto a max heap (in place). Then pop off the root node (i.e, max remaining value on heap) until you've popped all values off the heap. The values leave the heap in reverse sorted order, so as the heap shrinks, we can put popped values to the right end of the same array.

Sample code

object HeapSort {
 def main(args: Array[String]): Unit = {
 var mess = Array(3, 9, 8, 13, 2, 5, 4);
 sort(mess)
 // buildHeap(mess, mess.length-1)
 mess.foreach( println )
 }
 def sort(a: Array[Int]): Unit = {
 var m = a.length - 1 
 buildHeap(a, m)
 while (m >= 1) {
 swap(a, 0, m)
 m-=1
 heapify(a, 0, m)
 }
 }
 def buildHeap(a: Array[Int], m: Int): Unit = {
 for (i <- m/2 to 0 by -1) {
 heapify(a, i, m)
 }
 }
 /**Pushes an illegally located element down the heap to restore heap property.*/
 @annotation.tailrec
 def heapify(a: Array[Int], loc: Int, lastLeaf: Int): Unit = {
 val l = left(loc) 
 val r = right(loc)
 var max = loc
 if(l <= lastLeaf && a(l) > a(max)) max = l
 if(r <= lastLeaf && a(r) > a(max)) max = r
 if(max != loc) {
 swap(a, max, loc)
 heapify(a, max, lastLeaf)
 }
 }
 /**Returns position of left child (possibly empty). */
 def left(loc: Int): Int = {
 return 2*loc
 }
 /**Returns position of right child (possibly empty). */
 def right(loc: Int): Int = {
 return 2*loc+1
 }
 def swap(a: Array[Int], i: Int, j:Int): Unit = {
 val staging = a(i)
 a(i) = a(j)
 a(j) = staging
 }
}
answered Feb 1, 2017 at 9:00
\$\endgroup\$
4
  • 1
    \$\begingroup\$ You've presented an alternative solution without reviewing the code. On Code Review, all answers should contain a review. \$\endgroup\$ Commented Feb 1, 2017 at 9:46
  • \$\begingroup\$ Consider this: loc=0;left=1;right=2;Now think about your definition of left() and right(). Your code is correct if you assume arrays are indexed from 1. \$\endgroup\$ Commented Feb 1, 2017 at 16:39
  • \$\begingroup\$ Thanks for the code couple of questions. Why do you use recursion instead of a loop in heapify(). In my code when getting the children I use a tuple and one call. You use two calls (left() and right()). Is there a particular reason you choose to use two functions. Is my code bad practice or OK? \$\endgroup\$ Commented Feb 1, 2017 at 16:46
  • \$\begingroup\$ All your methods are public. I tried to hide members that were not useful to the public scope. Is that bad? \$\endgroup\$ Commented Feb 1, 2017 at 16:48

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.