zoukankan      html  css  js  c++  java
  • StringBuilder的实现与技巧(转)

    1.Length

     

    0.说明

    在上一篇进一步了解String 中,发现了string的不便之处,而string的替代解决方案就是StringBuilder的使用
    它的使用也很简单
    System.Text.StringBuilder sb =newSystem.Text.StringBuilder();
    这样就初始化了一个StringBuilder,之后我们可以通过Append()来追加字符串填充到sb中
    初始化StringBuilder 后,它会自动申请一个默认的StringBuilder 容量(默认值是16),
    这个容量是由Capacity来控制的.并且允许,我们根据需要来控制Capacity的大小,也可以通过Length来获取或设置StringBuilder 的长度

    1.Length的用法

    System.Text.StringBuilder sb =newSystem.Text.StringBuilder();
    sb.Append("123456789");//添加一个字符串
    sb.Length=3;//设置容量为3
    Console.WriteLine( sb.ToString());//这里输出:123
    sb.Length=30;//重新设置容量为30
    Console.WriteLine( sb.ToString()+",结尾");//这里在原来字符串后面补齐空格,至到Length的为30
    Console.WriteLine( sb.Length);//这里输出的长度为30
    通过上面的代码,我们可以看出如果StringBuilder 中的字符长度小于Length的值,则StringBuilder 将会用空格硬填充StringBuilder ,以满足符合长度的设置
    如果StringBuilder 中的字符长度大于Length的值,则StringBuilder 将会截取从第一位开始的Length个字符,而忽略超出的部分..
     

    2.Capacity

     

    1.代码

    System.Text.StringBuilder sb =newSystem.Text.StringBuilder();//初始化一个StringBuilder
    Console.Write("Capacity:"+ sb.Capacity);//这里的Capacity会自动扩大
    Console.WriteLine("	 Length:"+ sb.Length);
    sb.Append('1',17);//添加一个字符串,这里故意添加17个字符,是为了看到Capacity是如何被扩充的
    Console.Write("Capacity:"+ sb.Capacity);//这里的Capacity会自动扩大
    Console.WriteLine("	 Length:"+ sb.Length);
    sb.Append('2',32);//添加一个字符串
    Console.Write("Capacity:"+ sb.Capacity);//这里的Capacity会自动扩大
    Console.WriteLine("	 Length:"+ sb.Length);
    sb.Append('3',64);//添加一个字符串
    Console.Write("Capacity:"+ sb.Capacity);//这里的Capacity会自动扩大
    Console.WriteLine("	 Length:"+ sb.Length);
    //注意这里:如果你取消Remove这步操作,将会引发ArgumentOutOfRangeException异常,因为当前容量小于
    //Length,这在自己控制StringBuilder的时候务必要注意容量溢出的问题
    sb.Remove(0,sb.Length);//移出全部内容,再测试
    sb.Capacity=1;//重新定义了容量
    sb.Append('a',2);
    Console.Write("Capacity:"+ sb.Capacity);//这里的Capacity会自动扩大
    Console.WriteLine("	 Length:"+ sb.Length);
    sb.Append('b',4);
    Console.Write("Capacity:"+ sb.Capacity);//这里的Capacity会自动扩大
    Console.WriteLine("	 Length:"+ sb.Length);
    sb.Append('c',6);
    Console.Write("Capacity:"+ sb.Capacity);//这里的Capacity会自动扩大
    Console.WriteLine("	 Length:"+ sb.Length

    2.输出结果

    Capacity:16Length:0//输出第一次,默认的Capacity是16
    Capacity:32Length:17//第二次,我们故意添加了17个字符,于是Capacity=Capacity*2
    Capacity:64Length:49//继续超出,则Capacity=Capacity*2
    Capacity:128Length:113
    Capacity:3Length:2//清空内容后,设置Capacity=1,重新添加了字符
    Capacity:7Length:6//后面的结果都类似
    Capacity:14Length:12

    3.说明

    从上面的代码和结果可以说明StringBuilder中容量Capacity是如何增加的:
    创建一个StringBuilder之后,默认的Capacity初始化为16,接着我们添加17个字符,以方便看到Capacity的扩充后的值
    大家在修改Capacity的时候,一定要注意21行的注释,一定要确保Capacity >= Length,否则会引发ArgumentOutOfRangeException异常.
    看完结果,就可以推断出Capacity的公式:
    if ( Capacity < Length && Capacity > 0 ){
          Capacity *= 2;
    }

    OK..看到公式就明白了..StringBuilder是以当前的Capacity*2来扩充的
    所以,在使用StringBuilder需要特别注意,尤其是要拼接或追加N多字符的时候,要注意技巧的使用
    可以适当的,有预见性的设置Capacity的值,避免造成过大内存的浪费,节约无谓的内存空间
    例如,下列代码就可以根据情况自动的扩展,而避免了较大的内存浪费.
    System.Text.StringBuilder sb =newSystem.Text.StringBuilder();
    int i =0;
    longStartTime=DateTime.Now.Ticks;
    while( i <100000)
    {
    sb.Append( i.ToString());
    i++;
    }
    longEndTime=DateTime.Now.Ticks;
    Console.WriteLine("时间:"+(EndTime-StartTime)+"	 Capacity:"+ sb.Capacity+"	 Length:"
    + sb.Length);
    System.Text.StringBuilder sb1 =newSystem.Text.StringBuilder();
    i =0;
    StartTime=DateTime.Now.Ticks;
    while( i <100000)
    {
    if( sb1.Capacity<= sb1.Length)//先判断是否>Length
    {
    sb1.Capacity+=7;//这里一定要根据情况的增加容量,否则会有性能上的消耗
    }
    sb1.Append( i.ToString());
    i++;
    }
    EndTime=DateTime.Now.Ticks;
    Console.WriteLine("时间:"+(EndTime-StartTime)+"	 Capacity:"+ sb1.Capacity+"	
    Length:" + sb1.Length);
     
    需要特别说明的一点是,自动增加的容量,一定要根据实际预见的情况而改变,否则不但起不到优化的作用,反而会影响到程序的性能..

    3.StringBuilder.Append 与 string+的性能比较

     

    0.说明

    一旦你的string在堆中创建后,其在内存中都是以const存在,任何的修改都会使其被重新创建为新的string,而指向以前的string的引用将会指向这个新的string!!
    即每次string+操作,总会创建新的string,使得此操作占用内存空间大,耗时长。

    1.代码

    System.Text.StringBuilder sb =newSystem.Text.StringBuilder();
    int i =0;
    longStartTime=DateTime.Now.Ticks;
    while( i <100000) 
    {
        sb.Append( i.ToString());
        i++;
    }
    longEndTime=DateTime.Now.Ticks;
    Console.WriteLine("时间:"+(EndTime-StartTime));
    string sb1 =null;
    i =0;
    StartTime=DateTime.Now.Ticks;
    while( i <100000)
    {
        sb1 += i;
        i++;
    }
    EndTime=DateTime.Now.Ticks;
    Console.WriteLine("时间:"+(EndTime-StartTime));
    本人实测时间
    StringBuilder时间:    119964
    string+时间:             410746739

    2.总结

    连接少量字符串:使用string
    连接大量字符串:使用StringBuilder并注意对Capacity的控制



  • 相关阅读:
    51 Nod 1086 多重背包问题(单调队列优化)
    51 Nod 1086 多重背包问题(二进制优化)
    51 Nod 1085 01背包问题
    poj 2559 Largest Rectangle(单调栈)
    51 Nod 1089 最长回文子串(Manacher算法)
    51 Nod N的阶乘的长度 (斯特林近似)
    51 Nod 1134 最长递增子序列(经典问题回顾)
    51 Nod 1020 逆序排列
    PCA-主成分分析(Principal components analysis)
    Python中cPickle
  • 原文地址:https://www.cnblogs.com/moonache/p/5168741.html
Copyright © 2011-2022 走看看