[英]Permutation algorithm Optimization
我有這個排列代碼完美運行,但它生成代碼的速度不夠快,我需要幫助優化代碼以運行得更快,請務必保持結果不變,我見過其他算法,但他們沒有進入考慮 output 的長度和相同的字符信譽,它們都是有效的 output。如果我可以將其轉換為包含 28 個字母數字字符的 for 循環,那就太棒了。 下面是我要優化的當前代碼。
namespace CSharpPermutations
{
public interface IPermutable<T>
{
ISet<T> GetRange();
}
public class Digits : IPermutable<int>
{
public ISet<int> GetRange()
{
ISet<int> set = new HashSet<int>();
for (int i = 0; i < 10; ++i)
set.Add(i);
return set;
}
}
public class AlphaNumeric : IPermutable<char>
{
public ISet<char> GetRange()
{
ISet<char> set = new HashSet<char>();
set.Add('0');
set.Add('1');
set.Add('2');
set.Add('3');
set.Add('4');
set.Add('5');
set.Add('6');
set.Add('7');
set.Add('8');
set.Add('9');
set.Add('a');
set.Add('b');
return set;
}
}
public class PermutationGenerator<T,P> : IEnumerable<string>
where P : IPermutable<T>, new()
{
public PermutationGenerator(int number)
{
this.number = number;
this.range = new P().GetRange();
}
public IEnumerator<string> GetEnumerator()
{
foreach (var item in Permutations(0,0))
{
yield return item.ToString();
}
}
IEnumerator IEnumerable.GetEnumerator()
{
foreach (var item in Permutations(0,0))
{
yield return item;
}
}
private IEnumerable<StringBuilder> Permutations(int n, int k)
{
if (n == number)
yield return new StringBuilder();
foreach (var element in range.Skip(k))
{
foreach (var result in Permutations(n + 1, k + 1))
{
yield return new StringBuilder().Append(element).Append(result);
}
}
}
private int number;
private ISet<T> range;
}
class MainClass
{
public static void Main(string[] args)
{
foreach (var element in new PermutationGenerator<char, AlphaNumeric>(2))
{
Console.WriteLine(element);
}
}
}
}
感謝您的提前努力。
您在那里輸出的是兩組的笛卡爾積; 第一組是字符“0123456789ab”,第二組是字符“123456789ab”。
Eric Lippert 寫了一篇著名的文章演示如何使用 Linq 來解決這個問題。
我們可以像這樣將其應用於您的問題:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Demo;
static class Program
{
static void Main(string[] args)
{
char[][] source = new char[2][];
source[0] = "0123456789ab".ToCharArray();
source[1] = "0123456789ab".ToCharArray();
foreach (var perm in Combine(source))
{
Console.WriteLine(string.Concat(perm));
}
}
public static IEnumerable<IEnumerable<T>> Combine<T>(IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item }));
}
}
您可以通過修改源數據將其擴展到 28 個字符:
source[0] = "0123456789abcdefghijklmnopqr".ToCharArray();
source[1] = "0123456789abcdefghijklmnopqr".ToCharArray();
如果您想知道這是如何工作的,請閱讀我在上面鏈接的 Eric Lipper 的優秀文章。
考慮
foreach (var result in Permutations(n + 1, k + 1))
{
yield return new StringBuilder().Append(element).Append(result);
}
Permutations 是實現迭代器的遞歸 function。 因此,每次.MoveNext()
方法都會推進循環的一步,這將依次調用MoveNext()
等,導致 N 次調用MoveNext()
、 new StringBuilder
、 Append()
等。這是非常低效的。
A 也看不到 stringBuilder 在這里提供任何優勢。 如果您連接許多字符串,這是一個好處,但據我所知,您只將兩個字符串加在一起。
您應該做的第一件事是添加代碼來衡量性能,或者更好的是,使用分析器。 這樣您就可以判斷是否有任何更改確實改善了情況。
我要嘗試的第二個更改是嘗試將遞歸重寫為迭代實現。 這可能意味着您需要跟蹤要處理的數字的顯式堆棧。 或者,如果這太困難了,請停止使用迭代器塊,讓遞歸方法獲取一個列表,並將結果添加到其中。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.