Advertisement
CSharpFan

Permutations in C# (not generic)

Dec 19th, 2013
207
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 6.37 KB | None | 0 0
  1. using System;
  2.  
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Collections;
  7.  
  8.  
  9. namespace NumberStuff
  10. {
  11.     /// <summary>
  12.     /// Generates all permutations for a set of integers using the
  13.     /// Steinhaus Johnson Trotter permutation algorithm. It is
  14.     /// implemented as an itterator with a yield return statement
  15.     /// so each permutation is only generated when required. The
  16.     /// class can be called using the following code:
  17.     ///
  18.     ///        Permutations p = new Permutations(5);
  19.     ///
  20.     ///        foreach (int[] row in p.GeneratePermutation())
  21.     ///        {
  22.     ///            do something...
  23.     ///        }
  24.     ///        
  25.     ///  The constructor causes permutations for the set of integers 1 to 5 to be
  26.     ///  generated. See:
  27.     ///
  28.     ///  http://www.cut-the-knot.org/Curriculum/Combinatorics/JohnsonTrotter.shtml
  29.     ///
  30.     /// Note: this algorithm will only function correctly when the set of integers to be
  31.     /// permutated contains unique values. Duplicates, or more accurately when the duplicate
  32.     /// is of the highest value in the set, causes it to fail to generate all permutations.
  33.     ///        
  34.     /// </summary>
  35.     public sealed class Permutations
  36.     {
  37.         /// <summary>
  38.         /// Defines the direction of adjacent elements in an array
  39.         /// The numeric value is used to calculate the array index value
  40.         /// </summary>
  41.         private enum eDirection
  42.         {
  43.             left = -1,
  44.             right = 1
  45.         }
  46.  
  47.         /// <summary>
  48.         /// store for the current permutation
  49.         /// </summary>
  50.         private int[] digits;
  51.  
  52.  
  53.  
  54.         /// <summary>
  55.         /// Hide the default constructor
  56.         /// </summary>
  57.         private Permutations() { }
  58.  
  59.  
  60.         /// <summary>
  61.         /// Constructor used to generate permutations of n digits
  62.         /// This will always generate n! permutations
  63.         /// </summary>
  64.         /// <param name="digitCount">the number of digits</param>
  65.         /// <param name="offset">the initial value of the digits</param>      
  66.         public Permutations(int digitCount, int offset = 1)
  67.         {
  68.             digits = new int[digitCount];
  69.  
  70.             for (int index = 0; index < digitCount; index++)
  71.                 digits[index] = index + offset;
  72.         }
  73.  
  74.  
  75.  
  76.         /// <summary>
  77.         /// The itterator that generates each permutation as required
  78.         /// </summary>
  79.         /// <returns>
  80.         /// an array of integers containing the current permutation
  81.         /// </returns>
  82.         public System.Collections.IEnumerable GeneratePermutation()
  83.         {
  84.             // initialise the direction of adjacent digits
  85.             eDirection[] directions = new eDirection[digits.Length];
  86.  
  87.             for (int index = 0; index < directions.Length; index++)
  88.                 directions[index] = eDirection.left;
  89.  
  90.             // always sort the first permutation, this method could
  91.             // be called multiple times on the same instance
  92.             Array.Sort(digits);
  93.  
  94.             // yield and return the first permutation
  95.             yield return digits.ToArray();
  96.  
  97.             int mobileIndex;
  98.  
  99.             while (HasMobileInteger(directions, out mobileIndex))
  100.             {
  101.                 int mobileValue = digits[mobileIndex];
  102.  
  103.                 SwapIntegerWithAdjacent(directions, mobileIndex);
  104.  
  105.                 // yield and return sucessive permutations
  106.                 yield return digits.ToArray();
  107.  
  108.                 ChangeDirectionOfLargerThanMobileInteger(directions, mobileValue);                
  109.             }
  110.         }
  111.  
  112.  
  113.         /// <summary>
  114.         /// This method combines two functions in the original SJT algorithm these
  115.         /// are detecting if any mobile integers remain and also finding the index
  116.         /// of the mobile integer
  117.         /// </summary>
  118.         /// <param name="directions"></param>
  119.         /// <param name="mobileIndex"></param>
  120.         /// <returns></returns>
  121.         private bool HasMobileInteger(eDirection[] directions, out int mobileIndex)
  122.         {
  123.             int largestValue = int.MinValue;
  124.             mobileIndex = -1;
  125.  
  126.             for (int index = 0; index < directions.Length; index++)
  127.             {
  128.                 // first element
  129.                 if ((index == 0) && (directions[index] == eDirection.left))
  130.                     continue;
  131.  
  132.                 // last element
  133.                 if ((index == (digits.Length - 1)) && (directions[index] == eDirection.right))
  134.                     break;
  135.  
  136.                 // adjacent element is smaller
  137.                 if (digits[index + (int)directions[index]] < digits[index])
  138.                 {
  139.                     if (digits[index] > largestValue)
  140.                     {
  141.                         largestValue = digits[index];
  142.                         mobileIndex = index;
  143.                     }
  144.                 }
  145.             }
  146.  
  147.             return mobileIndex > -1;
  148.         }
  149.  
  150.  
  151.         /// <summary>
  152.         /// Swap with adjacent using the numeric value of the direction
  153.         /// to calculate required indexes. Swaps both the permutation digit
  154.         /// and its mapped direction
  155.         /// </summary>
  156.         /// <param name="directions"></param>
  157.         /// <param name="index"></param>
  158.         private void SwapIntegerWithAdjacent(eDirection[] directions, int index)
  159.         {
  160.             eDirection tempDirection = directions[index];
  161.             int tempValue = digits[index];
  162.            
  163.             directions[index] = directions[index + (int)tempDirection];
  164.             digits[index] = digits[index + (int)tempDirection];
  165.  
  166.             directions[index + (int)tempDirection] = tempDirection ;
  167.             digits[index + (int)tempDirection] = tempValue;
  168.         }
  169.  
  170.  
  171.         /// <summary>
  172.         /// After swapping this changes the direction of any larger digits
  173.         /// </summary>
  174.         /// <param name="directions"></param>
  175.         /// <param name="mobileValue"></param>
  176.         private void ChangeDirectionOfLargerThanMobileInteger(eDirection[] directions, int mobileValue)
  177.         {
  178.             for (int index = 0; index < digits.Length; index++)
  179.             {
  180.                 if (digits[index] > mobileValue)
  181.                     directions[index] = (eDirection)(0 - (int)directions[index]);                    
  182.             }
  183.         }
  184.     }
  185. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement