【java】实现txt文档中汉字频率排序及输出频率最高的前十个汉字
01. 目的
java编程实现统计文档中汉字出现的频率,将汉字出现频率按高频到低频排序,并输出频率最高的前十个汉字。
02. 主要实现方法
(1) 首先按行读出txt文档中的内容:.readLine();
按行读出后取出每行中的字符: .charAt(i);
(2) 构建了HashMap对象,用于存放文档中出现的汉字及其出现的频率。键对应字符,值对应字符出现的次数。
HashMap<Character,Integer> hm = new HashMap<Character,Integer>();
判断汉字是否重复出现(汉字即为map中的键):用map类的containsKey()方法;
取出该键中的值(即汉字出现的频率):.get(key) ;
(3)重写public int compare(Object o1, Object o2) 方法,用Comparator类中的compare(T o1,T o2)对汉字频率比较大小。
可参考博文:【Java】Collections.sort() 方法 —— Comparable、Comparator接口
compare(T o1, T o2)是中的o1,o2代表什么,是怎么实现排序的?怎么和compareTo()配合使用?
o1和o2每次只取一个数据,就一次只比较两个数据,假如比较7,8,9,5,6,那么第一次比较o1先取8,o2取7(很奇怪,我当时以为是顺着取值,但是很奇怪,他是相邻两个值逆着取值),接下来配合compareTo()实现这两个数的排序,o1.compareTo(o2)会返回一个int值,如果0说明o1和o2相等,如果返回负值,那么o1和o2会倒序排序,返回正值,那么o1和o2会正序排序。返回值之后这两个值就进行了排序,至此,这两个值已经排序好了,接下来第二次排序,o1取9,o2取8,第三次o1取5,o2取9…
(4)通过entrySet()方法将map集合中的映射关系取出导入List动态数组,用Collections.sort()对值进行排序
(5)使用迭代器Iterator取出map中的键和对应的值。
Iterator<Map.Entry<Character, Integer>> iter = list.iterator();
03. 程序代码(sequence.java)
/*
* 功能:* 对文档中汉字出现频率进行排序
* * 在控制台打印频率最高的前十个汉字
* @author WTCLAB_yd
*
*/
import java.io.*;//导入io类包
import java.util.*;//导入util类包
public class sequence {
public static void main(String[] args){
File file=new File(args[0]);//建立读入文件对象
BufferedReader buf=null;
try{
buf = new BufferedReader(new FileReader(file));//定义字符读取(缓冲)流并赋值
String value = null; //定义一个临时接收文件中的字符串变量
String newValue = ""; //接收文件中所有字符串的变量
while((value = buf .readLine())!=null){
for(int i=0;i<value.length();i++){//开始读取文件中的字符
if(value.charAt(i)>=0x4e00 && value.charAt(i)<=0x9fbb){
newValue = newValue+value.charAt(i); //存入newValue变量中
}
}
}
char[] ch = newValue.toCharArray();//把newValue变成字符数组(Collections. reverseOrder())
HashMap<Character,Integer> hm = new HashMap<Character,Integer>();//构建了一个新的HashMap对象,赋予变量hm.键对应字符,值对应字符出现的次数
for(int j = 0;j<ch.length;j++){ //遍历ch 将ch中所有的字符存入一个Map集合中,键对应字符,值对应字符出现的次数
char c = ch[j];
if(hm.containsKey(c)){ //如果HashMap(hm)中有该键,则取出该键中的值,也就是出现的次数
int conut = hm.get(c);//取出该键中的值(该键出现的次数)放入count
hm.put(c,conut+1); //存入把新值存入hm集合中,如果键相同的话, 新键会替换老键,值也随着变化了
}
else{
hm.put(c, 1); //如果没有出现该键就说明是第一次出现,然后就存入1次
}
}
//自定义比较器
Comparator<Map.Entry<Character, Integer>> descValue = new Comparator<Map.Entry<Character,Integer>>(){
@Override
public int compare(Map.Entry<Character, Integer> o1, Map.Entry<Character, Integer> o2) {// o1和o2每次只取一个数据,就一次只比较两个数据
int i1 = o1.getValue(); // 获取键的值(即字符对应出现的频率)
int i2 = o2.getValue();
if (i1 != i2) { //若不同字符出现的频率不等,则返回1或-1
return (i1 > i2) ? -1 : 1;//如果返回负值,那么i1和i2会倒序排序,返回正值,那么i1和i2会正序排序
}
else {
return 0;//返回0说明i1和i2相等
}
}
};
//取出map中的键和对应的值
Set<Map.Entry<Character, Integer>> set = hm.entrySet();//通过entrySet()方法将map集合中的映射关系取出(这个关系就是Map.Entry类型)
List<Map.Entry<Character, Integer>> list = new ArrayList<Map.Entry<Character, Integer>>(set);//创建一个List的对象,list这个链表中的元素是Map类型的元素
Collections.sort(list, descValue);//根据比较器返回值对值(频率)排序
//获得map的迭代器,用作遍历map中的每一个键值对
Iterator<Map.Entry<Character, Integer>> iter = list.iterator();
System.out.print("\n本文中出现次数最高的前十个字: \n");
for(int n=0;n<10;n++){ //取出迭代器中前十个键值对
Map.Entry<Character, Integer> map = iter.next();//获得键值对
char k = map.getKey();//获取map的键(对应文档中的字符)
int v = map.getValue();//获取键对应的值(字符出现的频率)
System.out.print("\n "+k+" —— "+v );
}
}
catch(IOException e){
System.out.println("文件读取错误");
}
finally{
try{
if(buf!=null)
buf.close();//关闭数据流
}
catch(IOException e){
System.out.println("文件关闭错误");
}
}
}
}
04. 结果演示
(1)test.txt 测试
(2) 西游记测试(xyj.txt)
找出西游记中出现次数最多的十个字:
05. 补:程序计时
对大文档进行汉字排序时用时较多,为了便于优化程序、对比程序效率,在程序中加计时器打印程序运行时间,便于观察。
程序代码:(TimeCount.java)
添加System.currentTimeMillis()方法
* 功能:* 对文档中汉字出现频率进行排序
* * 在控制台打印频率最高的前十个汉字
* *获取程序运行所需时间
* @author WTCLAB_yd
*
*/
import java.io.*;//导入io类包
import java.util.*;//导入util类包
public class TimeCount {
public static void main(String[] args){
double begin = System.currentTimeMillis(); // 程序开始时间,调用系统的当前时间,时间单位为毫秒
File file=new File(args[0]);//建立读入文件对象
BufferedReader buf=null;
try{
buf = new BufferedReader(new FileReader(file));//定义字符读取(缓冲)流并赋值
String value = null; //定义一个临时接收文件中的字符串变量
String newValue = ""; //接收文件中所有字符串的变量
while((value = buf .readLine())!=null){
for(int i=0;i<value.length();i++){//开始读取文件中的字符
if(value.charAt(i)>=0x4e00 && value.charAt(i)<=0x9fbb){
newValue = newValue+value.charAt(i); //存入newValue变量中
}
}
}
char[] ch = newValue.toCharArray();//把newValue变成字符数组(Collections. reverseOrder())
HashMap<Character,Integer> hm = new HashMap<Character,Integer>();//构建了一个新的HashMap对象,赋予变量hm.键对应字符,值对应字符出现的次数
for(int j = 0;j<ch.length;j++){ //遍历ch 将ch中所有的字符存入一个Map集合中,键对应字符,值对应字符出现的次数
char c = ch[j];
if(hm.containsKey(c)){ //如果HashMap(hm)中有该键,则取出该键中的值,也就是出现的次数
int conut = hm.get(c);//取出该键中的值(该键出现的次数)放入count
hm.put(c,conut+1); //存入把新值存入hm集合中,如果键相同的话, 新键会替换老键,值也随着变化了
}
else{
hm.put(c, 1); //如果没有出现该键就说明是第一次出现,然后就存入1次
}
}
//自定义比较器
Comparator<Map.Entry<Character, Integer>> descValue = new Comparator<Map.Entry<Character,Integer>>(){
@Override
public int compare(Map.Entry<Character, Integer> o1, Map.Entry<Character, Integer> o2) {// o1和o2每次只取一个数据,就一次只比较两个数据
int i1 = o1.getValue(); // 获取键的值(即字符对应出现的频率)
int i2 = o2.getValue();
if (i1 != i2) { //若不同字符出现的频率不等,则返回1或-1
return (i1 > i2) ? -1 : 1;//如果返回负值,那么i1和i2会倒序排序,返回正值,那么i1和i2会正序排序
}
else {
return 0;//返回0说明i1和i2相等
}
}
};
//取出map中的键和对应的值
Set<Map.Entry<Character, Integer>> set = hm.entrySet();//通过entrySet()方法将map集合中的映射关系取出(这个关系就是Map.Entry类型)
List<Map.Entry<Character, Integer>> list = new ArrayList<Map.Entry<Character, Integer>>(set);//创建一个List的对象,list这个链表中的元素是Map类型的元素
Collections.sort(list, descValue);//根据比较器返回值对值(频率)排序
//获得map的迭代器,用作遍历map中的每一个键值对
Iterator<Map.Entry<Character, Integer>> iter = list.iterator();
System.out.print("\n本文中出现次数最高的前十个字: \n");
for(int n=0;n<10;n++){ //取出迭代器中前十个键值对
Map.Entry<Character, Integer> map = iter.next();//获得键值对
char k = map.getKey();//获取map的键(对应文档中的字符)
int v = map.getValue();//获取键对应的值(字符出现的频率)
System.out.print("\n "+k+" —— "+v );
}
}
catch(IOException e){
System.out.println("文件读取错误");
}
finally{
try{
if(buf!=null)
buf.close();//关闭数据流
}
catch(IOException e){
System.out.println("文件关闭错误");
}
double end = System.currentTimeMillis(); // 程序结束时间,调用系统当前时间
double time = end - begin;// 程序的运行时间
System.out.println("\n程序用时:"+time/1000 + "秒");//输出执行完程序的用时,1ms=1/1000 s
}
}
}
结果演示:
程序用时:183.44秒