拆分字符串没有string.Split

时间:2012-01-30 16:25:36

标签: c# string

我正在做一个家庭工作问题,不使用框架方法拆分字符串。

以下是我提出的工作代码。

我想知道如何改善O(n)的运行时间?

欢迎任何有关改进的建议。

public static string[] split(string txt, char[] delim)
{
    char[] text = txt.ToCharArray();
    string[] result = new string[0];
    int count = 0;
    int i = 0;
    StringBuilder buff = new StringBuilder(); 
    while(i < text.Length)
    {
        bool found = false;
        foreach(char del in delim)
        {
            if(del == txt[i])
            {
                found = true;
                break;
            }
        }
        if(found)
        {
            count++;
            Array.Resize(ref result, count);
            result[count - 1] = buff.ToString();
            buff = new StringBuilder();                 
        }
        else
        {
            buff.Append(txt[i]);
        }

        i++;
    }

    if(buff.Length != 0)
    {
        count++;
        Array.Resize(ref result, count);
        result[count - 1] = buff.ToString();
    }

    return(result);
}

5 个答案:

答案 0 :(得分:6)

我有一些更改会同时使这个函数更像C,并将运行时间减少到O(n):

1)您应该多次动态调整result数组的大小,而不是动态调整txt.Length数组的大小,以保留最大数量的字符串(您知道该数字小于char[] buff),然后在返回之前,只在最后调整一次。

2)不要使用StringBuilder汇总结果,而是制作txt.Length长度为j且索引变量为buff[j++] = txt[i]并执行bool[] isDelimiter = new bool[128]; // increase size if you are allowing non-ascii foreach(char delim in isDelimiter) { isDelimiter[(int)char] = true; }

我认为你的功能应该是O(N)。从技术上讲,它将是O(N * M),其中M是分隔符的数量。

编辑1:

这是一个改变,使其为O(N)+ O(M)而不是O(N * M):

不是循环遍历字符串中每个字符的分隔符,而应循环遍历ADVANCE中的分隔符并设置如下数组:

{{1}}

然后你可以使用这个数组在恒定时间内测试字符串的每个字符。

答案 1 :(得分:2)

我认为你的教授正在寻找一种只需要一个字符的API,而不是一个数组。不是一个字符数组。我的意思是,如果你的分隔字符串是“abcd”,你就不会分裂'a','b','c','d'的所有实例。只有在找到整个字符串时才会拆分。

您当前的算法不是O(n),因为对于输入数组中的每个元素,您要将它与分隔数组的每个元素进行比较。这导致O(n * m)执行时间。

我认为不可能将其转换为O(n),因为输入上的每个元素都需要与分隔符数组的每个元素进行比较。我认为你的教授可能更有可能就分隔符数组问一个不同的问题。

public static String[] Split(String input, String delimiter)
{
    List<String> parts = new List<String>();
    StringBuilder buff = new StringBuilder();
    if (delimiter.Length > 1) //you are splitting on a string not a character
    {
       //perform string searching algorithm here
    }
    else if(delimiter.Length == 0)
    {
       throw new InvalidOperationException("Invalid delimiter.");
    }
    else //you are splitting on a character
    {
       char delimChar = delimiter[0];
       for (int i = 0; i < input.Length; i++)
       {
           if (input[i] == delimChar)
           {
               parts.Add(buff.ToString());
               buff.Clear();
           }
           else
           {
               buff.Append(input[i]);
           }
       }
    }
    return parts.ToArray();
}

C#的String.Split()确实接受了一系列分隔符,但我不相信它会在O(n)时间内进行分割。

如果您正在研究字符串搜索算法,这些可能会有所帮助。 http://en.wikipedia.org/wiki/String_searching_algorithm

编辑:我错误地提到了C#的String.Split() API未采用分隔符数组的事实。

答案 2 :(得分:1)

由于必须遍历/搜索分隔符列表,因此无法在O(n)中执行String.Split。

答案 3 :(得分:1)

如果将分隔符放入HashSet,则可以将其设为O(n)。测试HashSet中是否存在值是O(1)。

var delimterSet = new HashSet<char>(delim);

...

if(delimterSet.Contains(txt[i]) { ... }

但是,对于少数分隔符,这不会改善性能。

答案 4 :(得分:0)

也许你可以尝试一次完成所有的工作

public static String[] Split(String txt, char[] delim)
{
    if (txt == null)
        return new String[0]; // or exception
    if (delim == null || delim.Length == 0)
        return new String[0]; // or exception

    char[] text = txt.ToCharArray();
    string[] result = new string[1]; // If there is no delimiter in the string, return the whole string
    int part = 0;
    int itemInArray = 1;

    for (int i = 0; i < text.Length; i++)
    {
        if (IsIn(delim, text[i]))
        {
            Array.Resize(ref result, ++itemInArray); // Is it consider as a framework method ???
            part++;
        }
        else
            result[part] += text[i];
    }
    return result;
}
public static Boolean IsIn(char[] delim, char c)
{
    for (int i = 0; i < delim.Length; i++)
        if (c == delim[i])
            return true;
    return false;
}