从字符串中查找字符出现次数的方法和性能对比

今天在一场“特殊的讨论”中引入了一个问题,如何在C#求出字符串中某字符的出现次数,比如求“ADSFGEHERGASDF”中“A”出现的次数。首先想到的方法当然是从头遍历字符串并统计:

c1 = 0;
for (int i = 0; i < str.Length; i++)
{
    if (str[i] == 'A')
    {
        c1++;
    }
}

第二种方法也很容易想到,将字符串中所有要查找的字符去除,然后比较去除前后的字符串长度即可。这种方法遭到了某人的鄙视,据说性能很差而且多占空间。

c2 = str.Length - str.Replace("A", String.Empty).Length;

接下来某人又提出了第三种方法,是用要查找的字符为分隔符,将原字符串分隔为多个子串,然后求子串的数目即可。在C#中这是一个写起来很短的方法:

c3 = str.Split(new char[] { 'A' }).Length - 1;

我们从原理可以推断出三者性能的顺序,但究竟差距是多少呢,还是要动手试验一下。这是非常经典的测试代码:

string str = "SADTHDGSAFSDGTGHRDGSADFADDRHDFSGASDAA";

Stopwatch sw = new Stopwatch();

long t;
int c = 0;
GC.Collect();
Application.DoEvents();

sw.Start();

for (int i = 0; i < 100000; i++)
{
    c = 三种算法
}

sw.Stop();

t = sw.ElapsedMilliseconds;

首先我们确保正确性,经测试三种方法都能正确处理多种情况,包括首尾、连续出现、不出现或串长度为0等,我所取的字符串是一个很普通的串。编译为Release版,预运行10次后获得以下结果:

遍历统计:13毫秒
替换后比较长度:112毫秒
断开字符串后计数:233毫秒

这里已经体现出差异,遍历统计比替换后比较要快10倍,断开字符串又要慢一些。接下来我又做了如下两个测试:

1、不改变字符串的长度,增加或减少要查找字符串的个数。
2、不改变要查找字符出现的频率,但增长字符串的长度。

结果发现,三种方法都随字符串长度增加线性变慢,而后两种方法还随要查找的字符增加而变慢。断开字符串的方法还受要查找字符串分布情况的影响。

研究Replace函数和Split函数的实现可以彻底解决这个问题。不过我没有心情细细研究了,我还是决定选用第二种方法——替换后比较长度。虽然其速度比第一种方法慢,但易于改写为求长度不为1的子串出现次数的方法。第一种方法若改为求长度大于1的字串就要考虑很多因素(尽管不一定真的很麻烦),我懒得想了,呵呵。

 

 

 

 

 

 

 

最新找到的:

 

也不知道c#有没有现成的这样的函数来实现,现在紧张要用,有很多遍历的方法,因为我这个比较特殊,要在生成的sql语句里查询sum这个字符串出现的次数,也就是我要知道它sum来多少次,现在假设生成的sql语句变量为mysql,则:
int mylen=(mysql.Length - mysql.Replace("sum", "").Length) / 3;
 
这样不用遍历就可快速计算出字符串sum在字符串mysql中出现的次数了。
原理:计算出mysql原始长度-mysql去掉sum的长度,它们之差除以sum的长度就是出现的次数。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值