簡體   English   中英

排列算法優化

[英]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 StringBuilderAppend()等。這是非常低效的。

A 也看不到 stringBuilder 在這里提供任何優勢。 如果您連接許多字符串,這是一個好處,但據我所知,您只將兩個字符串加在一起。

您應該做的第一件事是添加代碼來衡量性能,或者更好的是,使用分析器。 這樣您就可以判斷是否有任何更改確實改善了情況。

我要嘗試的第二個更改是嘗試將遞歸重寫為迭代實現。 這可能意味着您需要跟蹤要處理的數字的顯式堆棧。 或者,如果這太困難了,請停止使用迭代器塊,讓遞歸方法獲取一個列表,並將結果添加到其中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM