计算和排序字符串数组的最佳方法是什么

时间:2012-02-13 17:17:54

标签: java sorting data-structures

我试图找到一种好的方法来搜索(计算出现次数),然后以有效的方式对String数组进行排序......这种方式在嵌入式系统中运行良好(32Mb)< / p>

示例:我必须计算使用角色A,B,C等的时间...保存后结果的结果......

我可以使用public int count(String searchDomain,char searchValue)方法计算,但每个字符串应该包含所有字母:

"This is a test string"
A:1,B:0,C:0,D:0,E:1,I:3,F:0,...
"ACAAGATGCCATTGTCCCCCGGCCTCCTGCTGCTGCTGCTCTCCGGGGCCACGGCCACCGCTGCCCTGCC"
A:7,B:0,C:22,G:18

我的排序方法需要能够回答以下事项:按As,Bs的数量排序 首先按As排序,然后按Bs

对该子域进行排序

这不适用于家庭作业,它适用于需要在手机上运行的应用程序,我需要高效,我目前的实现速度太慢而且占用的内存过多。

8 个答案:

答案 0 :(得分:11)

我会利用Java(非常高效)内置的排序功能。首先,定义一个简单的类来包含您的字符串及其元数据:

class Item
{
    // Your string. It's public, so you can get it if you want,
    // but also final, so you can't accidentally change it.
    public final String string;

    // An array of counts, where the offset is the alphabetical position
    // of the letter it's counting. (A = 0, B = 1, C=2...)
    private final short[] instanceCounts = new short[32];

    public Item(String string)
    {
        this.string = string;
        for(char c : string.toCharArray())
        {
            // Increment the count for this character
            instanceCounts[(byte)c - 65] ++;
        }
    }

    public int getCount(char c)
    {
        return instanceCounts[(byte)c - 65];
    }
}

这将保存您的String(用于搜​​索和显示),并设置一个带有匹配字符数的short数组。 (如果你的确实内存不足,并且你知道你的字符串中任何一个字符超过255,你甚至可以将其更改为一个字节数组。)一个short只有16个字节,所以无论你的字符串有多复杂,数组本身只会占用64个字节。如果您每次都要为计算计数而付出性能损失,那么您可以摆脱数组并替换getCount()方法,但您可能最终会通过频繁使用垃圾收集来节省一次性内存记忆,这是一个很大的表现。 :)

现在,使用Comparator定义要搜索的规则。例如,要按字符串中A的数量排序:

class CompareByNumberOfA implements Comparator<Item>
{
    public int compare(Item arg0, Item arg1) 
    {
        return arg1.getCount('A') - arg0.getCount('A');
    }
}

最后,将所有项目都放在一个数组中,并使用内置(和高内存效率)Arrays方法进行排序。例如:

public static void main(String args[])
{
    Item[] items = new Item[5];
    items[0]= new Item("ABC");
    items[1]= new Item("ABCAA");
    items[2]= new Item("ABCAAC");
    items[3]= new Item("ABCAAA");
    items[4]= new Item("ABBABZ");

    // THIS IS THE IMPORTANT PART!
    Arrays.sort(items, new CompareByNumberOfA());

    System.out.println(items[0].string);
    System.out.println(items[1].string);
    System.out.println(items[2].string);
    System.out.println(items[3].string);
    System.out.println(items[4].string);
}

你可以定义一大堆比较器,并按照你喜欢的方式使用它们。

使用Java编写代码要记住的一件事情不是太聪明。只要你利用他们可以优化的东西(比如包含Arrays.sort的内置API),编译器就可以很好地优化他们的平台。

通常情况下,如果你试图变得过于聪明,那么你就可以从有效的解决方案中优化自己。 :)

答案 1 :(得分:1)

我相信你所追求的是一个树形结构,实际上这个问题会更好地重写,谈论一个树结构来索引长连续字符串而不是“计数”或“排序”。

我不确定这是解决方案还是重述问题。你想要一个树的数据结构,根有例如树。 26个子树,一个用于以'A'开头的字符串,一个用于'B'的下一个子节点,依此类推;然后'A'孩子有例如代表“AB”,“AC”,“AT”等20名儿童;等等代表儿童的孩子,例如“ABALXYZQ”,其中每个子节点包含一个表示计数的整数字段,即子字符串出现的次数?

class AdamTree {
    char ch;
    List<AdamTree> children;
    int count;
}

如果这会占用太多内存,那么你就会想办法在内存中占用CPU时间,但这可能很难做到......没有任何想法。

答案 2 :(得分:1)

抱歉,我没有时间以更好的方式写这篇文章。为了最小化空间,我将制作一个2 m x n(密集)数组,一个字节和一个短路,其中:

  • m是输入字符串的数量
  • n是每个字符串中的字符数;此维度因行而异
  • 字节数组包含字符
  • 短数组包含该字符的计数

如果计数得到保证&lt; 256,你可以使用一个m x n x 2字节数组。

如果您使用的字符集很密集,即ANY字符串中使用的ALL字符集不比EACH字符串中使用的字符集大很多,您可以删除字节数组并使用一个固定的“n”(上面),带有一个从字符映射到索引的函数。这会快得多。

对于具有Q子句的任何查询,这将需要此数组的2Q遍历。希望这足够快。

答案 3 :(得分:0)

我可以帮助处理php /伪代码和hashmaps或关联数组。

$hash="";

$string = "ACAAGATGCCATTGTCCCCCGGCCTCCTGCTGCTGCTGCTCTCCGGGGCCACGGCCACCGCTGCCCTGCC"
while ( read each $char from $string ) {

  if ( isset($hash[$char]) ) { 
      $hash[$char] = $hash[$char]+1 
  } else {
      $hash[$char]=1
  }
}

最后你会得到一个关联数组,找到1个key / char 并且在哈希值中,您将获得出现的计数

这不是PHP(或任何其他语言),但原则应该有所帮助。

答案 4 :(得分:0)

http://en.wikipedia.org/wiki/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm 看看KMP算法。这是一个相当常见的编程问题。您可以在上方找到最快的解决方案之一。易于理解和实施。

使用KMP计算出现次数,然后在插入后使用合并排序,或者如果您知道数组/ etc已排序,则使用二进制搜索/方向插入。

答案 5 :(得分:0)

也许你可以使用一种树形结构,其中深度对应于给定的字母。因此,树中的每个节点对应于字母+该字母的出现次数。如果只有一个字符串与此节点(及其父节点)匹配,则它将存储在节点中。否则,该节点具有下一个字母和字母计数的子节点。

这样就可以得到这样的结果:

A:     0                  1                   3           ...
       |               /     \              /    \
B:     0             0        1           1        3
      / \          heaven   /   \     barracuda    ababab
C:   0   1                 0     1
   foo   cow             bar     bac

不确定这会比数组计数解决方案花费少,但至少你不必存储所有字符串的所有字母的计数(当字母计数唯一标识字符串时树停止)

你可以通过切割没有兄弟姐妹的长枝来优化它

答案 6 :(得分:0)

您可以尝试下面的Java代码

int[] data = new int[254];//we have 254 different characters 
void processData(String mString){

    for (int i=0 ; i< mString.length;i++){
       char c = mString.charAt(i); 
        data[c]++;
    }
}
int getCountOfChar(char c){
     return data[c];
}

答案 7 :(得分:0)

似乎对你的要求和目标有些困惑。

如果您的搜索结果占用太多空间,为什么不“压缩”(如音乐压缩)结果呢?有点像哈希函数。然后,当您需要检索结果时,您的哈希表示需要使用更长的搜索算法正确搜索的字符串的更小的子集。

如果您实际存储了String个对象,并且您的字符串实际上是人类可读的文本,那么在完成搜索和索引之后,您可以尝试使用java.util.zip缩小它们。如果确实希望保持它们很小并且您没有收到实际的String个对象,并且您说您只有26个不同的字母,则可以将它们压缩为5位组并存储他们就是这样。使用CharSequence界面。