这种类型的题,在许多互联网笔试面试中经常会遇到,今天在这详细的说明一下如何实现。具体解释后面有注释
废话不多说,直接上代码:
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CountsWord {
public static void main(String[] args) throws Exception {
BufferedReader readfile = new BufferedReader(new FileReader(
"C:\\test.txt"));/*首先将文件的内容读取到缓冲区bufferedreader中,利用
的是BufferedReader中的readline()读取文件中的每一个文本行,readline()并不是一行一行读取的,而是一个文本
行一个文本行读取。什么是文本行?看Java API中BufferedReader类总中的readline()的解释。*/
StringBuffer sb = new StringBuffer();
String text = null;
while ((text = readfile.readLine()) != null) {
sb.append(text);//将从文件中读出来的字符串追加,形成一个字符串
}
readfile.close();
Pattern patten = Pattern.compile("[a-zA-Z]+");/*用Pattern类中的complie()方法,将正则表达式编译到模式中*/
String sbstring = sb.toString();
Matcher matcher = patten.matcher(sbstring);/*用Pattern类中的matcher()方法,生成一个匹配
器对象,Matcher类是匹配器类*/
Map
while (matcher.find()) {/*用Matcher类中的find()方法,查找与模式匹配的下一个子序列*/
String word = matcher.group();/*用Matcher类中的group()方法, 返回匹配的子序列*/
if (tp.containsKey(word)) {//统计每个单词出现的次数
Integer wordfrequency = tp.get(word);
tp.put(word, wordfrequency + 1);
} else {
tp.put(word, 1);
}
}
List
tp.entrySet());/*将treemap中的键值对的set视图存入ArrayList中,其中的类
型必须是Map.Entry,因为TreeMap中的entrySet()方法的返回类型就是Map.Entry类型,其实Map.Entry就是个接口。
将treemap存入ArrayList的目的就是用Collections类中的sort()方法进行排序,其中的sort(List
list,Comparator)是按照指定的比较器进行排序*/
Comparator
Integer>>() {/*重写Comparator比较器,目的是让TreeMap按照value进行降序排列,这里的重写比较器用的是匿名
类,也就是是先创建实现Comparator接口的类,并重写其中的compare方法,并不是接口实例化了。如果觉得用匿名
类这种方式实现比较器重写,你还可以单独写个类MyComparator实现接口Comparator,并重写compare()方法,在
sort(List
public int compare(Map.Entry
return (param2.getValue().compareTo(param1.getValue());/*如果是实现升序就是return (param1.getValue().compareTo(param2.getValue());具体解释看下面的解释*/
}
};
Collections.sort(list, comparator);//按照指定的比较器,对list列表进行升序或者降序排序
for (int i = 0; i < 5; i++) {
String key = list.get(i).getKey();
Integer value = list.get(i).getValue();
System.out.println(key + ":" + value);
}
}
}
可能有些人对重写比较器Comparator和sort()如何完成排序的有些疑惑,这里就我个人观点进行说明,如有不对
的地方,还请大家指正。比较器中的compare方法只是负责将两个参数比较的结果返回,并不负责进行排序。进行排
序的是sort()方法,它根据compare()方法的返回值进行相应排序。第一个参数小于第二个参数 返回负数 ;第一个
参数大于第二个参数 返回正数;第一个参数等于第二个参数 返回0。
java的api中这个方法
sort(List
api的解释是:根据指定比较器产生的顺序对指定列表进行排序。
Comparator里的compare方法在api里解释是:比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个
参数分别返回负整数、零或正整数。
问题:重写Comparator里的compare方法,compare根据传进去的两个对象进行对比后返回一个整数,compare只是
返回了一个整数来表明<,=,>,但是并没有根据compare的返回结果对这两个对象进行某种排序,那么最后比较器是
怎么产生顺序的?
sort方法怎么实现,可以查看源码
但是一般思路都是从升序开始(可能人的意识是看到排序最初的印象是升序),但是因为sort本身是个模板,也
就是希望sort不改变,由用户传入的比较器来决定排序,所以6L的伪代码就是基于升序的基础去处理的,sort里面只
需要关心比较器的返回值,如果返回值大于0,则说明比较参数1大于比较参数2,则把参数1"沉底"(换过来说就是参
数2冒泡),这样当用户改变比较器,原本参数1大于参数2应该返回大于0的,可用户却故意返回小于0,这样相当于
比较器欺骗了sort,sort因为只关心结果,于是就认为参数2大于参数1,于是把参数2"沉底"(参数1冒泡),这样就
相当于把“小”的放到最底,于是也就成了“降序”排序。
所以,排序的模板一般来说都是基于升序实现的,如果要达到“降序”,就由用户去实现比较器然后传给sort方法就可以了