[英]Implementation of heaps algorithm
Please I don't seem to know what is wrong with this my C# implementation of the heaps permutation algorithm. 请我似乎不知道我的C#实现堆置换算法的问题是什么。 It does not give the correct permutation of an input array.
它不能给出输入数组的正确排列。 Can somebody help me out?
有人可以帮我吗?
Here is the pseudo-code 这是伪代码
procedure generate(n : integer, A : array of any):
if n = 1 then
output(A)
else
for i := 0; i < n - 1; i += 1 do
generate(n - 1, A)
if n is even then
swap(A[i], A[n-1])
else
swap(A[0], A[n-1])
end if
end for
generate(n - 1, A)
end if
this is my c# Implementation 这是我的C#实现
static void Permute(int[] A, int n) {
if (n == 1) {
printArray(A);
} else {
for (int i = 0; i < n - 1; i++) {
Permute(A, n - 1);
if (n % 2 == 0) {
A = Swap(A, A[i], A[n - 1]);
printArray(A);
} else {
A = Swap(A, A[0], A[n - 1]);
printArray(A);
}
}
Permute(A, n - 1);
}
}
static int[] Swap(int[] A, int x, int y) {
int temp;
temp = A[x];
A[x] = A[y];
A[y] = temp;
return A;
}
static void printArray(int[] A) {
foreach(var x in A) {
Console.Write(x);
}
Console.WriteLine();
}
Looks for me, that your meaning about the swap function, as you defined, expects to get the array and indexes of the swapped values. 在我看来,您所定义的关于交换函数的含义希望获得交换值的数组和索引。
So instead of: 所以代替:
Swap(A, A[i], A[n - 1]);
Swap(A, A[0], A[n - 1]);
Should be: 应该:
Swap(A, i, n - 1);
Swap(A, 0, n - 1);
By the way, if you had this algorithm for array of any other type than int[]
you whould get compilation error in the swap call. 顺便说一句,如果您有此算法用于除
int[]
以外的任何其他类型的数组,则在swap调用中将出现编译错误。 You haven't have compilation error because of the coincidence that your array elements are of the same type as array index type: int
您还没有编译错误,因为巧合的是,你的数组元素都是同一类型的数组索引类型的:
int
And another thing, even though its not an issue, it is not necessary to return the array, from Swap function. 另外,即使这不是问题,也不必从Swap函数返回数组。 The first argument of the Swap, the array is passed by reference, so the Swap function works on the same array instance as in the caller function and not on its copy.
交换的第一个参数是数组,是通过引用传递的,因此交换函数与调用方函数在相同的数组实例上工作,而不是在其副本上工作。 So after you remove the unnecessary return from Swap, the printArray(A);
因此,从Swap中删除了不必要的收益之后,printArray(A); called right after the Swap will print the same as you have now.
在“交换”之后立即调用,将打印与您现在的相同的内容。
public static IEnumerable<IEnumerable<T>> Permute<T>(this IList<T> v)
{
ICollection<IList<T>> result = new List<IList<T>>();
Permute(v, v.Count, result);
return result;
}
private static void Permute<T>(IList<T> v, int n, ICollection<IList<T>> result)
{
if (n == 1)
{
result.Add(new List<T>(v));
}
else
{
for (var i = 0; i < n; i++)
{
Permute(v, n - 1, result);
Swap(v, n % 2 == 1 ? 0 : i, n - 1);
}
}
}
private static void Swap<T>(IList<T> v, int i, int j)
{
var t = v[i];
v[i] = v[j];
v[j] = t;
}
Just as information for anybody... 就像任何人的信息...
You could achieve a really better performance by doing some adjustments: 通过进行一些调整,您可以实现更好的性能:
Just as a reference, I included my implementation of it. 仅供参考,我包括了它的实现。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
namespace WpfPermutations
{
/// <summary>
/// EO: 2016-04-14
/// Generator of all permutations of an array of anything.
/// Base on Heap's Algorithm. See: https://en.wikipedia.org/wiki/Heap%27s_algorithm#cite_note-3
/// </summary>
public static class Permutations
{
/// <summary>
/// Heap's algorithm to find all pmermutations. Non recursive, more efficient.
/// </summary>
/// <param name="items">Items to permute in each possible ways</param>
/// <param name="funcExecuteAndTellIfShouldStop"></param>
/// <returns>Return true if cancelled</returns>
public static bool ForAllPermutation<T>(T[] items, Func<T[], bool> funcExecuteAndTellIfShouldStop)
{
int countOfItem = items.Length;
if (countOfItem <= 1)
{
return funcExecuteAndTellIfShouldStop(items);
}
var indexes = new int[countOfItem];
for (int i = 0; i < countOfItem; i++)
{
indexes[i] = 0;
}
if (funcExecuteAndTellIfShouldStop(items))
{
return true;
}
for (int i = 1; i < countOfItem;)
{
if (indexes[i] < i)
{ // On the web there is an implementation with a multiplication which should be less efficient.
if ((i & 1) == 1) // if (i % 2 == 1) ... more efficient ??? At least the same.
{
Swap(ref items[i], ref items[indexes[i]]);
}
else
{
Swap(ref items[i], ref items[0]);
}
if (funcExecuteAndTellIfShouldStop(items))
{
return true;
}
indexes[i]++;
i = 1;
}
else
{
indexes[i++] = 0;
}
}
return false;
}
/// <summary>
/// This function is to show a linq way but is far less efficient
/// From: StackOverflow user: Pengyang : http://stackoverflow.com/questions/756055/listing-all-permutations-of-a-string-integer
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
/// <param name="length"></param>
/// <returns></returns>
static IEnumerable<IEnumerable<T>> GetPermutations<T>(IEnumerable<T> list, int length)
{
if (length == 1) return list.Select(t => new T[] { t });
return GetPermutations(list, length - 1)
.SelectMany(t => list.Where(e => !t.Contains(e)),
(t1, t2) => t1.Concat(new T[] { t2 }));
}
/// <summary>
/// Swap 2 elements of same type
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="a"></param>
/// <param name="b"></param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
/// <summary>
/// Func to show how to call. It does a little test for an array of 4 items.
/// </summary>
public static void Test()
{
ForAllPermutation("123".ToCharArray(), (vals) =>
{
Console.WriteLine(String.Join("", vals));
return false;
});
int[] values = new int[] { 0, 1, 2, 4 };
Console.WriteLine("Ouellet heap's algorithm implementation");
ForAllPermutation(values, (vals) =>
{
Console.WriteLine(String.Join("", vals));
return false;
});
Console.WriteLine("Linq algorithm");
foreach (var v in GetPermutations(values, values.Length))
{
Console.WriteLine(String.Join("", v));
}
// Performance Heap's against Linq version : huge differences
int count = 0;
values = new int[10];
for (int n = 0; n < values.Length; n++)
{
values[n] = n;
}
Stopwatch stopWatch = new Stopwatch();
ForAllPermutation(values, (vals) =>
{
foreach (var v in vals)
{
count++;
}
return false;
});
stopWatch.Stop();
Console.WriteLine($"Ouellet heap's algorithm implementation {count} items in {stopWatch.ElapsedMilliseconds} millisecs");
count = 0;
stopWatch.Reset();
stopWatch.Start();
foreach (var vals in GetPermutations(values, values.Length))
{
foreach (var v in vals)
{
count++;
}
}
stopWatch.Stop();
Console.WriteLine($"Linq {count} items in {stopWatch.ElapsedMilliseconds} millisecs");
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.