我正在创建一个程序,需要检查每个可能的排列。让我们说我们有1,2,3这个程序会运行得很好并向我展示所有可能的程序:1,3,2 2,1,3 2,3,1 3,1,2和3, 2,1但是我也希望它能够尝试这样的组合
1,1,1
2,2,2-
1,2,2-
3,3,2
即包括绝对所有可能的组合..这是我的代码:
public static bool NextPermutation<T>(T[] elements) where T : IComparable<T>
{
// More efficient to have a variable instead of accessing a property
var count = elements.Length;
// Indicates whether this is the last lexicographic permutation
var done = true;
// Go through the array from last to first
for (var i = count - 1; i > 0; i--)
{
var curr = elements[i];
// Check if the current element is less than the one before it
if (curr.CompareTo(elements[i - 1]) < 0)
{
continue;
}
// An element bigger than the one before it has been found,
// so this isn't the last lexicographic permutation.
done = false;
// Save the previous (bigger) element in a variable for more efficiency.
var prev = elements[i - 1];
// Have a variable to hold the index of the element to swap
// with the previous element (the to-swap element would be
// the smallest element that comes after the previous element
// and is bigger than the previous element), initializing it
// as the current index of the current item (curr).
var currIndex = i;
// Go through the array from the element after the current one to last
for (var j = i + 1; j < count; j++)
{
// Save into variable for more efficiency
var tmp = elements[j];
// Check if tmp suits the "next swap" conditions:
// Smallest, but bigger than the "prev" element
if (tmp.CompareTo(curr) < 0 && tmp.CompareTo(prev) > 0)
{
curr = tmp;
currIndex = j;
}
}
// Swap the "prev" with the new "curr" (the swap-with element)
elements[currIndex] = prev;
elements[i - 1] = curr;
// Reverse the order of the tail, in order to reset it's lexicographic order
for (var j = count - 1; j > i; j--, i++)
{
var tmp = elements[j];
elements[j] = elements[i];
elements[i] = tmp;
}
// Break since we have got the next permutation
// The reason to have all the logic inside the loop is
// to prevent the need of an extra variable indicating "i" when
// the next needed swap is found (moving "i" outside the loop is a
// bad practice, and isn't very readable, so I preferred not doing
// that as well).
break;
}
// Return whether this has been the last lexicographic permutation.
return done;
}
这是我如何使用它的一个简单例子
var arr = new[] {0, 1, 2,};
var conditions = new[] {true, false, true};
int count = 0;
while (!NextPermutation(arr))
{
List<bool> tempConditions = new List<bool>();
for (int i = 0; i < arr.Length; i++)
{
tempConditions.Add(conditions[arr[i]]);
Console.Write(tempConditions[i] + " ");
}
count++;
Console.WriteLine();
}
Console.WriteLine("count : {0}", count);
答案 0 :(得分:2)
1,1,2 2,2,2这些不是排列 - 它们是变体。将有计数^计数
您可以像这样生成它们:
// you can do precise powering if needed
double number_of_variations = Math.Pow(count, count);
T[] result = new T[count];
for (int i = 0; i < number_of_variations; ++i) {
int x = i;
for (int j = 0; j < count; ++j) {
result[j] = elements[x % count];
x /= count;
}
// do something with one of results
}
答案 1 :(得分:2)
您可以使用返回IEnumerable<IEnumerable<T>>
的方法执行此操作:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo
{
public static class Program
{
public static void Main()
{
string[] test = {"A", "B", "C", "D"};
foreach (var perm in PermuteWithRepeats(test))
Console.WriteLine(string.Join(" ", perm));
}
public static IEnumerable<IEnumerable<T>> PermuteWithRepeats<T>(IEnumerable<T> sequence)
{
return permuteWithRepeats(sequence, sequence.Count());
}
private static IEnumerable<IEnumerable<T>> permuteWithRepeats<T>(IEnumerable<T> sequence, int count)
{
if (count == 0)
{
yield return Enumerable.Empty<T>();
}
else
{
foreach (T startingElement in sequence)
{
IEnumerable<T> remainingItems = sequence;
foreach (IEnumerable<T> permutationOfRemainder in permuteWithRepeats(remainingItems, count - 1))
yield return new[]{startingElement}.Concat(permutationOfRemainder);
}
}
}
}
}