DCSIMG
Interview Question #6 - Three way partition - generic solution - IHateSpaghetti {code}

IHateSpaghetti {code}

VSX, DSL and Beyond by Eyal Lantzman

Syndication

Coding / Architecture

Extensibility /DSL

Projects

Articles

Interview Question #6 - Three way partition - generic solution

This post is a part of the Interview Question Series posts.

Three way partition?! Is there a two way partition or a four way partition ?!

Well X way partition problems are simply dividing the array/collection into X compartments each with it's own distinct feature/property.

One way compartment sort is too simple (just return the array without doing anything) :-)

Two compartments are not difficult as well - you just need to pointers one to the left side one to the right side and you advance the pointers from both sides towards middle when you can't move you swap between them. And the main loop is running while the left side hasn't crossed the right side. If you want the code just drop me a line...

The complexity is greatly increases when the number of compartments is more then two (and you bound to a memory complexity of O(1) - otherwise one could create a list per compartment, go through the source array and map the items to the corresponding list and at the end just merge the lists by the needed order).

So, what are our options - we can sort using some sort efficient sort - O(NlogN). Quite good but can we do better ? The answer is yes (otherwise I wouldn't bother...)

   1: namespace Question6_ThreeWayPartition
   2: {
   3:   /// <summary>
   4:   /// Question: When given unsorted array of integers sort the array so that in the beggining will be all
   5:   /// the negative numbers (unordered), then zeros and then all the positives (unordered)
   6:   /// </summary>
   7:   class Program
   8:   {
   9:     static void Main(string[] args)
  10:     {
  11:       //test the sorting using 10 random arrays
  12:       for (int i = 0; i < 10; i++)
  13:       {
  14:         //generate the random array and a copy (in order to test in the two methods)
  15:         int[] array = Generate(15);
  16:         
  17:         //print the original
  18:         Console.Write("\nOrigianl array: ");
  19:         PrintArray(array);
  20:  
  21:         SortUsingThreeWayPartition(array);
  22:         Console.Write("\nModified array: ");
  23:         PrintArray(array);
  24:       }
  25:  
  26:       Console.ReadLine();
  27:     }
  28:  
  29:     /// <summary>
  30:     /// Random array generator (range is [-3,3])
  31:     /// </summary>
  32:     /// <param name="length">size of array</param>
  33:     /// <returns>the array</returns>
  34:     private static int[] Generate(int length)
  35:     {
  36:       int[] array = new int[length];
  37:       Random randomGenerator = new Random();
  38:       for (int i = 0; i < array.Length; i++)
  39:       {
  40:         array[i] = randomGenerator.Next(-3, 4); //between -3 and 3 in order to give enough chance for the zeros
  41:       }
  42:       return array;
  43:     }
  44:  
  45:     /// <summary>
  46:     /// Sorting method
  47:     /// </summary>
  48:     /// <param name="array"></param>
  49:     public static void SortUsingThreeWayPartition(int[] array)
  50:     {
  51:       int firstPartition = 0, secondPartition = 0, thirdPartition = array.Length - 1;
  52:  
  53:       while (secondPartition <= thirdPartition)
  54:       {
  55:         if (array[secondPartition] > 0)
  56:         {
  57:           Swap(array, secondPartition, thirdPartition--); //move to the third partition
  58:         }
  59:         else if (array[secondPartition] < 0)
  60:         {
  61:           Swap(array, firstPartition++, secondPartition++); //move to the first partition
  62:         }
  63:         else
  64:         {
  65:           secondPartition++; // leave in the second partition
  66:         }
  67:       }
  68:     }
  69:  
  70:     /// <summary>
  71:     /// Swaps between two values in array
  72:     /// </summary>
  73:     /// <param name="array"></param>
  74:     /// <param name="i"></param>
  75:     /// <param name="j"></param>
  76:     private static void Swap(int[] array, int i, int j)
  77:     {
  78:       if (i == j)
  79:         return;
  80:  
  81:       int temp = array[i];
  82:       array[i] = array[j];
  83:       array[j] = temp;
  84:     }
  85:     
  86:     /// <summary>
  87:     /// Simple method that prints the array
  88:     /// </summary>
  89:     /// <param name="array"></param>
  90:     private static void PrintArray(int[] array)
  91:     {
  92:       foreach (int i in array)
  93:       {
  94:         Console.Write(i);
  95:         Console.Write(" ");
  96:       }
  97:       Console.WriteLine();
  98:     }
  99:   }
 100: }

You can generalize the algorithm using generics by providing a mapping function that maps the item to specific compartment (1, 2 or 3)  as following:

   1: /// <summary>
   2: /// Sorting method
   3: /// </summary>
   4: /// <param name="array"></param>
   5: /// <param name="mapper">mapping function where to move the item:
   6: /// 1 - 1st partition 
   7: /// 2 - 2nd partition
   8: /// 3 - 3rd partition
   9: /// </param>
  10: /// <typeparam name="T">array item type</typeparam>
  11: public static void SortUsingThreeWayPartition<T>(T[] array, Func<T, int> mapper)
  12: {
  13:   int firstPartition = 0, secondPartition = 0, thirdPartition = array.Length - 1;
  14:  
  15:   while (secondPartition <= thirdPartition)
  16:   {
  17:     int partition = mapper(array[secondPartition]);
  18:     switch (partition)
  19:     {
  20:       case 1:
  21:         Swap(array, firstPartition++, secondPartition++); //move to the first partition
  22:         break;
  23:       case 2:
  24:         secondPartition++; // leave in the second partition
  25:         break;
  26:       case 3:
  27:         Swap(array, secondPartition, thirdPartition--); //move to the third partition
  28:         break;
  29:     }
  30:   }
  31: }
  32:  
  33: /// <summary>
  34: /// Swaps between two generic items in array
  35: /// </summary>
  36: /// <typeparam name="T">array item type</typeparam>
  37: /// <param name="array"></param>
  38: /// <param name="i"></param>
  39: /// <param name="j"></param>
  40: private static void Swap<T>(T[] array, int i, int j)
  41: {
  42:   if (i == j)
  43:     return;
  44:   T temp = array[i];
  45:   array[i] = array[j];
  46:   array[j] = temp;
  47: }

And in order to solve the problem above all you need is to create the correct mapping as following:

   1: //For the problem above you can using the following code:
   2: SortUsingThreeWayPartition<int>(arrayCopy,
   3:   //mapper anonymous function
   4:   (num) => 
   5:   {
   6:     //if num is negative - map to the 1st partition
   7:     if (num < 0)
   8:       return 1;
   9:     //if num is zero - map to the 2nd partition
  10:     else if (num == 0)
  11:       return 2;
  12:     //if num is positive - map to the 3rd partition
  13:     else return 3;
  14:   });
Published Sunday, February 15, 2009 10:00 AM by Eyal

Comments

No Comments

Leave a Comment

(required) 
(required) 
(optional)
(required) 

Enter the numbers above: