C# 如何优化字符串重写规则程序

C# 如何优化字符串重写规则程序,c#,multithreading,optimization,C#,Multithreading,Optimization,我有一个小程序,它不断重写相同的字符串 string a = "aRbFR"; string b = "LFaLb"; string str = "Fa"; for (; n < 50; ++n) { for(Int64 i = 0; i < str.Length; ++i) { if (i < str.Length && str[(int)i] == 'a') { str = str.R

我有一个小程序,它不断重写相同的字符串

string a = "aRbFR";
string b = "LFaLb";
string str = "Fa";

for (; n < 50; ++n)
{
    for(Int64 i = 0; i < str.Length; ++i)
    {
        if (i < str.Length && str[(int)i] == 'a')
        {
            str = str.Remove((int)i, 1);
            str = str.Insert((int)i, a);
            i += a.Length;
        }

        if (i < str.Length && str[(int)i] == 'b')
        {
            str = str.Remove((int)i, 1);
            str = str.Insert((int)i, b);
            i += b.Length;
        }
    } 
}
例如:n0=Fa,n1=FaRbFR,n2=FaRbFRRLFaLbFR

由于我需要按顺序不断更新同一个变量,这对多线程来说可能吗?我想我可以让str变得易变,但我想不出它将如何正常工作,因为所有线程都需要更新相同的变量


如何在有效的时间内完成此操作?这需要花费很长时间,变量仍然处于相当低的索引n=17,在考虑线程性能之前,最好改进算法。事实证明,这适用于堆栈,因为它只是创建一棵树并将其展平。时间复杂度急剧下降

还请注意,由于这基本上是递归的,并且数据需求呈指数增长,因此即使是堆栈也会在更高级别上耗尽内存。尽管如此,您还是可以使用磁盘缓冲区,因为它是一个堆栈

另一个问题是分配,因此,一旦针对堆栈进行分配,在这里会有所帮助,因为它与StringBuilder一样在内部更高效地增长

堆栈版本

示例结果5次迭代,因为我最初弄错了,所以我最好把结果放在

堆叠

原创的


在考虑线程性能之前,最好先改进算法。事实证明,这适用于堆栈,因为它只是创建一棵树并将其展平。时间复杂度急剧下降

还请注意,由于这基本上是递归的,并且数据需求呈指数增长,因此即使是堆栈也会在更高级别上耗尽内存。尽管如此,您还是可以使用磁盘缓冲区,因为它是一个堆栈

另一个问题是分配,因此,一旦针对堆栈进行分配,在这里会有所帮助,因为它与StringBuilder一样在内部更高效地增长

堆栈版本

示例结果5次迭代,因为我最初弄错了,所以我最好把结果放在

堆叠

原创的


将军是对的,它只是在穿越一棵树。您可以使用堆栈来实现这一点,但不是显式堆栈,我的第一个选择工具是隐式堆栈,也称为递归

protected void makeA(int level, StringBuilder sb)
{
    if (level == 0)
    {
        sb.Append('a');
    }
    else
    {
        makeA(level - 1, sb);
        sb.Append("R");
        makeB(level - 1, sb);
        sb.Append("FR");
    }
}

protected void makeB(int level, StringBuilder sb)
{
    if (level == 0)
    {
        sb.Append('b');
    }
    else
    {
        sb.Append("LF");
        makeA(level - 1, sb);
        sb.Append("L");
        makeB(level - 1, sb);
    }
}

protected string makeString(int level)
{
    StringBuilder sb = new StringBuilder();
    sb.Append("F");
    makeA(level, sb);
    return sb.ToString();
}
该代码更简单,速度大约是普通版本的五倍。但这并不重要。50次迭代的字符串太大了。这两个计数相等:

double c1 = makeString(i).Count(c => c == 'a' || c == 'b');
double c2 = Math.Pow(2, i);

2^50=1125899906842624,即2.2PB,仅用于这两个字符1个字符2个字节。

一般是正确的,它只是在遍历一棵树。您可以使用堆栈来实现这一点,但不是显式堆栈,我的第一个选择工具是隐式堆栈,也称为递归

protected void makeA(int level, StringBuilder sb)
{
    if (level == 0)
    {
        sb.Append('a');
    }
    else
    {
        makeA(level - 1, sb);
        sb.Append("R");
        makeB(level - 1, sb);
        sb.Append("FR");
    }
}

protected void makeB(int level, StringBuilder sb)
{
    if (level == 0)
    {
        sb.Append('b');
    }
    else
    {
        sb.Append("LF");
        makeA(level - 1, sb);
        sb.Append("L");
        makeB(level - 1, sb);
    }
}

protected string makeString(int level)
{
    StringBuilder sb = new StringBuilder();
    sb.Append("F");
    makeA(level, sb);
    return sb.ToString();
}
该代码更简单,速度大约是普通版本的五倍。但这并不重要。50次迭代的字符串太大了。这两个计数相等:

double c1 = makeString(i).Count(c => c == 'a' || c == 'b');
double c2 = Math.Pow(2, i);


2^50=1125899906842624,也就是说,这两个字符只有2.2PB,1个字符2个字节。

所以,s0=Fa。然后是s1=Fs0,更一般地说,sn=Fsn-1。你怎么能并行化呢?在完成当前步骤之前,你无法进行下一步。如果速度较慢,请考虑使用StringBuilder执行此操作。在循环中进行字符串连接几乎总是错误的。是的,我就是这么想的。我会调查的,但我使用的是删除和插入。我假设你们并没有PB级的RAM,所以,你们需要另一种方法。你到底需要它做什么?string类是不可变的。如果您更改了一个字符串,那么旧的字符串是垃圾,并且您指向一个新字符串,无论它是插入、删除还是连接,因此,s0=Fa。然后是s1=Fs0,更一般地说,sn=Fsn-1。你怎么能并行化呢?在完成当前步骤之前,你无法进行下一步。如果速度较慢,请考虑使用StringBuilder执行此操作。在循环中进行字符串连接几乎总是错误的。是的,我就是这么想的。我会调查的,但我使用的是删除和插入。我假设你们并没有PB级的RAM,所以,你们需要另一种方法。你到底需要它做什么?string类是不可变的。如果您更改了一个字符串,那么旧字符串就是垃圾,您可以指向一个新字符串,无论它是插入、删除还是连接。谢谢您的回答。它真的更快!但就在50级的时候,它给了我一个内存不足的异常!我需要完成50级。还有什么想法吗?它会破坏大约3.5GB的内存。因此,我无法进行toString调用。可能当我退出该方法时,堆栈将被释放,并为程序提供更多空间。对于级别==0,代码无法正常工作。我不会说这是一个bug,但值得知道。@Greggz.net对字符串的大小有严格的限制,这取决于您的答案是32或64个ArchitectureAnks。它真的更快!但就在50级的时候,它给了我一个内存不足的异常

! 我需要完成50级。还有什么想法吗?它会破坏大约3.5GB的内存。因此,我无法进行toString调用。可能当我退出该方法时,堆栈将被释放,并为程序提供更多空间。对于级别==0,代码无法正常工作。我不会说这是一个bug,但它值得知道。@Greggz.net对字符串的大小有严格的限制,这取决于32或64体系结构。是的,我可以看出这是如何更快,但是它不处理其他组合,不管怎样,很好的工作方式。在你看来,在我的机器中计算整个路径是不可能的吗?一个包含整个路径的.txt文件将是~1TB,对吗?可以计算它,估计计算时间约为一年,但不可能存储在典型的计算机上。包含结果的文件将有几PB大。1PB=1000TB。整件事从一开始就是一个XY问题,而不是XY问题。如果你熟悉这个问题,F,R,L是我需要遵循的指令来找到坐标。我需要读10^12F的步骤。所以我试图找到一种存储信息的方法,现在我知道这是不可能的,然后我发现在将步长值加倍后,坐标有一个方程。所以我只计算了244140625步的值。然后用方程11次,直到我达到10^12步。是的,我可以看出这是如何更快,但它不处理其他组合,无论如何,很好的工作在你看来是不可能的计算整个路径在我的机器?一个包含整个路径的.txt文件将是~1TB,对吗?可以计算它,估计计算时间约为一年,但不可能存储在典型的计算机上。包含结果的文件将有几PB大。1PB=1000TB。整件事从一开始就是一个XY问题,而不是XY问题。如果你熟悉这个问题,F,R,L是我需要遵循的指令来找到坐标。我需要读10^12F的步骤。所以我试图找到一种存储信息的方法,现在我知道这是不可能的,然后我发现在将步长值加倍后,坐标有一个方程。所以我只计算了244140625步的值。然后用这个方程11次,直到我达到10^12步。
FaRbFRRLFaLbFRRLFaRbFRLLFaLbFRRLFaRbFRRLFaLbFRLLFaRbFRLLFaLbFRRLFaRbFRRLFaLbFRRLFaRbFRLLFaLbFRLLFaRbFRRLFaLbFRLLFaRbFRLLFaLbFR
protected void makeA(int level, StringBuilder sb)
{
    if (level == 0)
    {
        sb.Append('a');
    }
    else
    {
        makeA(level - 1, sb);
        sb.Append("R");
        makeB(level - 1, sb);
        sb.Append("FR");
    }
}

protected void makeB(int level, StringBuilder sb)
{
    if (level == 0)
    {
        sb.Append('b');
    }
    else
    {
        sb.Append("LF");
        makeA(level - 1, sb);
        sb.Append("L");
        makeB(level - 1, sb);
    }
}

protected string makeString(int level)
{
    StringBuilder sb = new StringBuilder();
    sb.Append("F");
    makeA(level, sb);
    return sb.ToString();
}
double c1 = makeString(i).Count(c => c == 'a' || c == 'b');
double c2 = Math.Pow(2, i);