Java 如何优化此代码?

Java 如何优化此代码?,java,optimization,build-time,Java,Optimization,Build Time,我当前的项目让我们在Java中使用TreeSet和TreeMap,并从文本文件中读取10514个歌曲元素的输入数组。每首歌都包含一个艺术家、标题和歌词字段。这个项目的目的是使用集合和地图对歌词进行快速搜索 首先,我迭代输入歌曲数组,访问歌词字段并创建一个Scanner对象以使用以下代码迭代歌词:commonWords是一个不应该是键的单词树集,lyricWords是单词到歌曲的整体映射 public void buildSongMap() { for (Song song:songs)

我当前的项目让我们在Java中使用TreeSet和TreeMap,并从文本文件中读取10514个歌曲元素的输入数组。每首歌都包含一个艺术家、标题和歌词字段。这个项目的目的是使用集合和地图对歌词进行快速搜索

首先,我迭代输入歌曲数组,访问歌词字段并创建一个Scanner对象以使用以下代码迭代歌词:
commonWords
是一个不应该是键的单词树集,
lyricWords
是单词到歌曲的整体映射

public void buildSongMap() {
    for (Song song:songs) {
        //method variables
        String currentLyrics= song.getLyrics().toLowerCase(); 
        TreeSet<Song> addToSet=null;
        Scanner readIn= new Scanner(currentLyrics);
        String word= readIn.next();

        while (readIn.hasNext()) {

            if (!commonWords.contains(word) && !word.equals("") && word.length()>1) {
                if (lyricWords.containsKey(word)) {
                    addToSet= lyricWords.get(word);
                    addToSet.add(song);
                    word=readIn.next();
                } else 
                    buildSongSet(word);

            } else 
                word= readIn.next();
        }

    }
public void buildSongMap(){
用于(歌曲:歌曲){
//方法变量
字符串currentLyps=song.getLyps().toLowerCase();
TreeSet addToSet=null;
扫描仪读入=新扫描仪(当前歌词);
String word=readIn.next();
while(readIn.hasNext()){
如果(!commonWords.contains(word)&&!word.equals(“”&&word.length()>1){
if(抒情词.containsKey(词)){
addToSet=lyricWords.get(word);
addToSet.add(歌曲);
word=readIn.next();
}否则
构建歌曲集(word);
}否则
word=readIn.next();
}
}
为了构建歌曲集,我使用以下代码:

public void buildSongSet(String word) {     
    TreeSet<Song> songSet= new TreeSet<Song>();
    for (Song song:songs) {
        //adds song to set 
        if (song.getLyrics().contains(word)) {
            songSet.add(song);
        }
    }
    lyricWords.put(word, songSet);
    System.out.println("Word added "+word);
}
public void buildSongSet(字符串词){
TreeSet songSet=新TreeSet();
用于(歌曲:歌曲){
//将歌曲添加到场景中
if(song.getlymps().contains(word)){
歌曲集。添加(歌曲);
}
}
歌词。放(词,歌曲集);
System.out.println(“添加单词”+单词);
}

现在,由于buildSongSet是从循环内部调用的,因此创建映射只需N^2次。当输入数组为4首歌曲时,搜索运行速度非常快,但当使用10514个元素的完整数组时,在一台2.4GHz、内存为6 GiB的机器上构建映射可能需要15分钟以上的时间。我可以做些什么来提高代码的效率?不幸的是,减少输入数据无效。

看起来您的buildSongSet正在做冗余工作。您的块:

if (lyricWords.containsKey(word)) {
    addToSet= lyricWords.get(word);
    addToSet.add(song);
    word=readIn.next();
} 
将歌曲添加到现有集。因此,当您发现一个不知道的单词时,只需向其中添加一首歌曲。将buildSongSet更改为:

public void buildSongSet(String word, Song firstSongWithWord) {     
    TreeSet<Song> songSet= new TreeSet<Song>();
    songSet.add(firstSongWithWord);
    lyricWords.put(word, songSet);
    System.out.println("Word added "+word);
}
public void buildSongSet(String word,Song firstsong with word){
TreeSet songSet=新TreeSet();
歌曲集。添加(第一首歌曲WithWord);
歌词。放(词,歌曲集);
System.out.println(“添加单词”+单词);
}
剩下的要迭代的歌曲将从第一段代码中添加到歌曲集中,如果它们包含那个词的话。我认为这样应该可以

编辑刚刚看到这是家庭作业…所以删除了HashSet建议

好吧,假设你把这些歌曲和歌词按顺序排列:

  • 宋一福
  • 歌曲2-富吧
  • 歌曲3-富吧
Song 1将看到foo不包含歌词,因此它将调用buildSongSet并为foo创建一个集合。它将自己添加到包含foo的集合中

歌曲2将看到foo在lyricWords中,并将其自身添加到集合中。它将看到bar不在集合中,并创建集合并添加自身。它不需要遍历以前的歌曲,因为第一次看到单词是在歌曲2中

歌曲3遵循同样的逻辑

你可以尝试优化代码的另一件事是找出一种不处理歌词中重复单词的方法。如果你的歌词是foo-foo-foo-bar-foo-bar-bar-foo-bar-bar-bar-foo-bar-bar-bar-bar-foo-bar-bar-bar-bar-foo-bar-bar-bar-bar-bar-foo-bar-bar-bar-bar-bar-bar-foo-bar-bar-bar-bar-bar-bar-foo-bar-bar-bar-


编辑另请参见-那里有额外的加速,但大的加速正在摆脱内部循环-很高兴现在已降到15秒。

看起来您的buildSongSet正在做冗余工作。您的块:

if (lyricWords.containsKey(word)) {
    addToSet= lyricWords.get(word);
    addToSet.add(song);
    word=readIn.next();
} 
将歌曲添加到现有集。因此,当您发现一个不知道的单词时,只需向其中添加一首歌曲。将buildSongSet更改为:

public void buildSongSet(String word, Song firstSongWithWord) {     
    TreeSet<Song> songSet= new TreeSet<Song>();
    songSet.add(firstSongWithWord);
    lyricWords.put(word, songSet);
    System.out.println("Word added "+word);
}
public void buildSongSet(String word,Song firstsong with word){
TreeSet songSet=新TreeSet();
歌曲集。添加(第一首歌曲WithWord);
歌词。放(词,歌曲集);
System.out.println(“添加单词”+单词);
}
剩下的要迭代的歌曲将从第一段代码中添加到歌曲集中,如果它们包含那个词的话。我认为这样应该可以

编辑刚刚看到这是家庭作业…所以删除了HashSet建议

好吧,假设你把这些歌曲和歌词按顺序排列:

  • 宋一福
  • 歌曲2-富吧
  • 歌曲3-富吧
Song 1将看到foo不包含歌词,因此它将调用buildSongSet并为foo创建一个集合。它将自己添加到包含foo的集合中

歌曲2将看到foo在lyricWords中,并将其自身添加到集合中。它将看到bar不在集合中,并创建集合并添加自身。它不需要遍历以前的歌曲,因为第一次看到单词是在歌曲2中

歌曲3遵循同样的逻辑

你可以尝试优化代码的另一件事是找出一种不处理歌词中重复单词的方法。如果你的歌词是foo-foo-foo-bar-foo-bar-bar-foo-bar-bar-bar-foo-bar-bar-bar-bar-foo-bar-bar-bar-bar-foo-bar-bar-bar-bar-bar-foo-bar-bar-bar-bar-bar-bar-foo-bar


编辑还可以看到-那里有额外的加速,但是大的加速已经摆脱了内部循环-很高兴现在降到了15秒。

请尝试将TreeSet更改为HashSet。我看不到您从何处获得TreeSet的好处。

请尝试将TreeSet更改为HashSet。我看不到您从何处获得TreeSet的好处

imho不需要整个
buildSongSet()
方法,因为您的主循环已将歌曲按单词添加到集合中。您唯一缺少的是为新词添加一个集合,例如:

if (lyricWords.containsKey(word)) {
    addToSet= lyricWords.get(word);
} else {
    addToSet = new TreeSet();
    lyricWords.put(word, addToSet);
}
addToSet.add(song);

你没有解决的一个问题就是那首歌