Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Collections;
- namespace NumberStuff
- {
- /// <summary>
- /// Generates all permutations for a set of integers using the
- /// Steinhaus Johnson Trotter permutation algorithm. It is
- /// implemented as an itterator with a yield return statement
- /// so each permutation is only generated when required. The
- /// class can be called using the following code:
- ///
- /// Permutations p = new Permutations(5);
- ///
- /// foreach (int[] row in p.GeneratePermutation())
- /// {
- /// do something...
- /// }
- ///
- /// The constructor causes permutations for the set of integers 1 to 5 to be
- /// generated. See:
- ///
- /// http://www.cut-the-knot.org/Curriculum/Combinatorics/JohnsonTrotter.shtml
- ///
- /// Note: this algorithm will only function correctly when the set of integers to be
- /// permutated contains unique values. Duplicates, or more accurately when the duplicate
- /// is of the highest value in the set, causes it to fail to generate all permutations.
- ///
- /// </summary>
- public sealed class Permutations
- {
- /// <summary>
- /// Defines the direction of adjacent elements in an array
- /// The numeric value is used to calculate the array index value
- /// </summary>
- private enum eDirection
- {
- left = -1,
- right = 1
- }
- /// <summary>
- /// store for the current permutation
- /// </summary>
- private int[] digits;
- /// <summary>
- /// Hide the default constructor
- /// </summary>
- private Permutations() { }
- /// <summary>
- /// Constructor used to generate permutations of n digits
- /// This will always generate n! permutations
- /// </summary>
- /// <param name="digitCount">the number of digits</param>
- /// <param name="offset">the initial value of the digits</param>
- public Permutations(int digitCount, int offset = 1)
- {
- digits = new int[digitCount];
- for (int index = 0; index < digitCount; index++)
- digits[index] = index + offset;
- }
- /// <summary>
- /// The itterator that generates each permutation as required
- /// </summary>
- /// <returns>
- /// an array of integers containing the current permutation
- /// </returns>
- public System.Collections.IEnumerable GeneratePermutation()
- {
- // initialise the direction of adjacent digits
- eDirection[] directions = new eDirection[digits.Length];
- for (int index = 0; index < directions.Length; index++)
- directions[index] = eDirection.left;
- // always sort the first permutation, this method could
- // be called multiple times on the same instance
- Array.Sort(digits);
- // yield and return the first permutation
- yield return digits.ToArray();
- int mobileIndex;
- while (HasMobileInteger(directions, out mobileIndex))
- {
- int mobileValue = digits[mobileIndex];
- SwapIntegerWithAdjacent(directions, mobileIndex);
- // yield and return sucessive permutations
- yield return digits.ToArray();
- ChangeDirectionOfLargerThanMobileInteger(directions, mobileValue);
- }
- }
- /// <summary>
- /// This method combines two functions in the original SJT algorithm these
- /// are detecting if any mobile integers remain and also finding the index
- /// of the mobile integer
- /// </summary>
- /// <param name="directions"></param>
- /// <param name="mobileIndex"></param>
- /// <returns></returns>
- private bool HasMobileInteger(eDirection[] directions, out int mobileIndex)
- {
- int largestValue = int.MinValue;
- mobileIndex = -1;
- for (int index = 0; index < directions.Length; index++)
- {
- // first element
- if ((index == 0) && (directions[index] == eDirection.left))
- continue;
- // last element
- if ((index == (digits.Length - 1)) && (directions[index] == eDirection.right))
- break;
- // adjacent element is smaller
- if (digits[index + (int)directions[index]] < digits[index])
- {
- if (digits[index] > largestValue)
- {
- largestValue = digits[index];
- mobileIndex = index;
- }
- }
- }
- return mobileIndex > -1;
- }
- /// <summary>
- /// Swap with adjacent using the numeric value of the direction
- /// to calculate required indexes. Swaps both the permutation digit
- /// and its mapped direction
- /// </summary>
- /// <param name="directions"></param>
- /// <param name="index"></param>
- private void SwapIntegerWithAdjacent(eDirection[] directions, int index)
- {
- eDirection tempDirection = directions[index];
- int tempValue = digits[index];
- directions[index] = directions[index + (int)tempDirection];
- digits[index] = digits[index + (int)tempDirection];
- directions[index + (int)tempDirection] = tempDirection ;
- digits[index + (int)tempDirection] = tempValue;
- }
- /// <summary>
- /// After swapping this changes the direction of any larger digits
- /// </summary>
- /// <param name="directions"></param>
- /// <param name="mobileValue"></param>
- private void ChangeDirectionOfLargerThanMobileInteger(eDirection[] directions, int mobileValue)
- {
- for (int index = 0; index < digits.Length; index++)
- {
- if (digits[index] > mobileValue)
- directions[index] = (eDirection)(0 - (int)directions[index]);
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement