Lexicographic(字典顺序)
给定一个[2,12]之间的整数n,升序返回int[]集合,数组里的数字代表索引。譬如n = 4时,返回
0123,0132,0213,0231,0312,0321,1023,1032,1203,1230,1302,1320,
2013,2031,2103,2130,2301,2310,3012,3021,3102,3120,3201,3210
对于任意n个元素的集合,根据索引选取对应元素就可以得到该集合的所有排列。因为排列个数为N!,13!溢出,所以N<13.
/// <summary>
/// 返回所有<paramref name="n"/>位数排列
/// </summary>
public static IEnumerable<int[]> Lexicographic(int n)
{
if (n < 2 || n > 12)
throw new ArgumentOutOfRangeException("n should be greater than 1 and less than 13");
var aux = new int[n + 1];
for (var i = 0; i < aux.Length; ++i)
aux[i] = i;
var result = new List<int[]>();
while (true)
{
var permutation = aux.Skip(1).Select(num => num - 1).ToArray();
result.Add(permutation);
var index1 = n - 1;
while (aux[index1] >= aux[index1 + 1])
--index1;
if (index1 == 0) break;
var index2 = n;
while (aux[index1] >= aux[index2])
--index2;
Swap(aux, index1, index2);
++index1;
index2 = n;
while (index1 < index2)
Swap(aux, index2--, index1++);
}
return result;
}
public static void Swap<T>(T[] array, int index1, int index2)
{
var tmp = array[index1];
array[index1] = array[index2];
array[index2] = tmp;
}
Adjacent Interchages(邻位交换)
通过交换相邻两位直到所有元素交换完毕
/// <summary>
/// 返回所有<paramref name="n"/>位数排列
/// </summary>
public static IEnumerable<int[]> PlainChange(int n)
{
if (n < 2 || n > 12)
throw new ArgumentOutOfRangeException("n should be greater than 1 and less than 13");
var aux = new int[n + 1];
for (var i = 0; i < aux.Length; ++i)
aux[i] = i;
var inversion = new int[n + 1];
var direction = new int[n + 1];
for (var i = 1; i < direction.Length; ++i)
direction[i] = 1;
var result = new List<int[]>();
var flag = true;
while (flag)
{
var permutation = aux.Skip(1).Select(num => num - 1).ToArray();
result.Add(permutation);
int index1 = n, index2 = 0;
while (true)
{
var index3 = inversion[index1] + direction[index1];
if (index3 >= 0)
{
if (index3 == index1)
{
if (index1 == 1)
{
flag = false;
break;
}
++index2;
}
else
{
Swap(aux, index1 + index2 - inversion[index1], index1 + index2 - index3);
inversion[index1] = index3;
break;
}
}
direction[index1] = -direction[index1];
--index1;
}
}
return result;
}
Cyclic Shift(循环移位)
/// <summary>
/// 返回所有<paramref name="n"/>位数排列
/// </summary>
public static IEnumerable<int[]> CyclicShift(int n)
{
if (n < 2 || n > 12)
throw new ArgumentOutOfRangeException("n should be greater than 1 and less than 13");
var aux = new int[n + 1];
for (int i = 1; i < aux.Length; ++i)
aux[i] = i;
var cmp = aux.ToArray();
var result = new List<int[]>();
while (true)
{
var permutation = aux.Skip(1).Select(num => num - 1).ToArray();
if (result.Count != 0 && permutation.SequenceEqual(result[0])) break;
result.Add(permutation);
var index = n;
while (index > 1)
{
var temp = aux[1];
for (int i = 2; i <= index; ++i)
aux[i - 1] = aux[i];
aux[index] = temp;
if (aux[index] != cmp[index]) break;
--index;
}
}
return result;
}
Ehrlich's Swap Method(这几个中最好的排列方法)
依次交换最左边的元素和剩余元素,例如
/// <summary>
/// 返回所有<paramref name="n"/>位数排列
/// </summary>
public static IEnumerable<int[]> Ehrlich(int n)
{
if (n < 2 || n > 12)
throw new ArgumentOutOfRangeException("n should be greater than 1 and less than 13");
int[] aux = new int[n];
int[] temp = new int[n];
for (int i = 0; i < n; ++i)
{
aux[i] = i;
temp[i] = i;
}
int[] control = new int[n + 1];
var result = new List<int[]>();
while (true)
{
result.Add(aux.ToArray());
var index1 = 1;
if (control[index1] == index1)
while (control[index1] >= index1)
control[index1++] = 0;
if (index1 == n) break;
++control[index1];
Swap(aux, 0, temp[index1]);
var index2 = 1;
if (index2 < --index1)
while (index2 < index1)
Swap(temp, index1--, index2++);
}
return result;
}