这个Java算法如何更快

时间:2012-01-24 15:44:37

标签: java algorithm binary linked-list ascii

我有这个循环,它将布尔的LinkedList拆分为8位,并返回缓冲区中每个字节的ASCII值。该函数返回字符串缓冲区。

如果LinkedList的大小很大,这段代码非常慢。我尝试用简单的循环来改变Iterator,但它仍然很慢。

这个算法怎么能真快?也许有多线程?

注意: linkList的大小并不总是可以被8整除。

public String toString(){

        String buffer = "";
        String output = "";

        LinkedList<Boolean> bits = this.bits;

        for(Iterator it = this.bits.iterator(); it.hasNext();){
            if(buffer.length() >= 8){
                output += (char)Integer.parseInt(buffer, 2);
                buffer = "";
            }

            buffer += ((Boolean)it.next() == false) ? "0" : "1";
        }

        if(buffer != "")
            output += (char)Integer.parseInt(buffer, 2);

        return output;
}

7 个答案:

答案 0 :(得分:8)

这些建议将为您提供足够的性能,同时保持代码简单易读。首先使用这些更改进行测试,如果不符合您的性能要求,请慢慢引入其他答案中建议的优化技术

  1. 使用BitSet代替LinkedList<Boolean>
  2. 使用StringBuilder output;代替String output;
  3. 使用StringBuilder buffer;代替String buffer;
  4. 使用Integer.valueOf()代替Integer.parseIntvalueOf使用缓存来估算低于128的值。

答案 1 :(得分:7)

  1. 使用StringBuilder初始化预期的输出容量:

    StringBuilder out = new StringBuilder(bits.size() / 8 + 1);
    
  2. 使用按位运算代替parseInt(),如下所示:

    int i = 0;          
    int c = 0;
    for(Boolean b: bits){
        if (i > 0 && i % 8 == 0){
            out.append((char) c);
            c = 0;
        }
        c = (c << 1) | (b ? 1 : 0);
        i++;
    }
    out.append((char) c); // Not sure about the desired behaviour here
    

答案 2 :(得分:2)

字符串连接速度很慢,特别是对于大型列表(因为字符串是不可变的,必须复制它们需要花费一些时间,每个副本也需要更多空间)。使用StringBuilder代替String进行追加。换句话说:bufferoutput应为StringBuilder个实例。

答案 3 :(得分:2)

正如其他人建议的那样 - 使用BitSet。对于其他人,我认为下面的方法非常有效:

    public String toString() {
        char[] bytes = new char[bits.size() / 8 + ((bits.size() % 8 > 0) ? 1 : 0)];
        int bitCounter = 0;
        int word = 0;
        int byteCounter = 0;
        for (boolean b : bits) {
            word = (word << 1) | (b ? 1 : 0);
            if (bitCounter == 7) {
                bytes[byteCounter] = (char) word;
                ++byteCounter;
                bitCounter = 0;
                word = 0;
            } else {
                ++bitCounter;
            } // else
        } // foreach
        bytes[byteCounter] = (char) word;
        return new String(bytes);
    } // toString() method

这可能是一个不使用字节计数器的更好的选择:

        public String toString() {
            int size = bits.size() / 8 + ((bits.size() % 8 > 0) ? 1 : 0);
            if (size == 0) {
                return "";
            } // if
            char[] bytes = new char[size];
            int bitCounter = 0;
            int word = 0;
            for (boolean b : bits) {
                if (bitCounter % 8 == 0
                        && bitCounter > 0) {
                    bytes[(bitCounter - 1) / 8] = (char) word;
                    word = 0;
                } // if
                word = (word << 1) | (b ? 1 : 0);
                ++bitCounter;
            } // foreach
            bytes[size - 1] = (char) word;
            return new String(bytes);
        } // toString() method

答案 4 :(得分:1)

尝试将缓冲区保留为int。我的意思是

 buffer = buffer << 1 + (((Boolean)it.next() == false) ? 0 : 1);

而不是

 buffer += ((Boolean)it.next() == false) ? "0" : "1";

还可以使用StringBuilder作为输出。这是一个很小的变化,但总是有点。

答案 5 :(得分:1)

尝试以下方法:

 StringBuilder b = new StringBuilder();
 int ch = 0;
 int n = 0;

 for (Boolean bit : bits) {
   ch <<= 1;
   if (bit) {
     ch++;
   }
   if (++n == 8) {
     b.append((char)ch);
     n = 0;
     ch = 0;
   }
 }

 if (n > 0) {
   b.append((char)ch);
 }  

 System.out.println(b.toString());

答案 6 :(得分:0)

对缓冲区和输出变量使用StringBuffer或stringBuilder而不是String。

String vars是不可变的,因此每个操作都在堆中创建一个新实例,而StringBuilder和StringBuffer则不是。