zoukankan      html  css  js  c++  java
  • 分析一个文本文件中各个词出现的频率

    要求:

      写一个程序,分析一个文本文件中各个词出现的频率,并且把频率最高的10个词打印出来。文本文件大约是30KB~300KB大小。
     

    解决步骤:

      1、读取一个 txt 文本文件;
      2、统计文件里面每个词出现的次数;
      3、进行排序,打印出频率最高的10个词。
     
    编程语言:java;
    测试文本:D:wordtest.txt         大小:417 KB (427,605 字节)
    性能测试工具:JDK自带的 VisualVM插件

    初步思路:

      1、将文件内容存放在 StringBuffer 里面;
      2、利用 split() 函数分割字符串,按照 ","、"."、"?"、":"、"空格"、"回车" 来分割,得到一个数组;
      3、遍历数组,将其放入 Map<String,Integer> 中,key=词,value=出现次数;
      4、对Map 进行排序,得到出现频率最高的10个词;

    程序实现:

     1 package homework;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.FileNotFoundException;
     5 import java.io.FileReader;
     6 import java.io.IOException;
     7 import java.util.HashMap;
     8 import java.util.Iterator;
     9 import java.util.Map;
    10 import java.util.Set;
    11 import java.util.StringTokenizer;
    12 import java.util.TreeSet;
    13 
    14 public class FileWordsCount {
    15     public static void main(String[] args) {
    16         
    17         long time1 = System.currentTimeMillis();
    18         
    19         try {
    20             BufferedReader br = new BufferedReader(new FileReader("D:\wordtest.txt"));
    21             String s;
    22             StringBuffer sb = new StringBuffer();
    23             while((s = br.readLine())!= null){
    24                 sb.append(s);
    25             }
    26             Map<String,Integer> map = new HashMap<String,Integer>();
    27             StringTokenizer st = new StringTokenizer(sb.toString(), ",.! ?
    ");
    28             while(st.hasMoreTokens()){
    29                 String letter = st.nextToken();
    30                 int count;
    31                 if(map.get(letter) == null){
    32                     count = 1;
    33                 }else{
    34                     count = map.get(letter).intValue()+1;
    35                 }
    36                 map.put(letter, count);
    37             }
    38             Set<WordEntity> set = new TreeSet<WordEntity>();
    39             for(String key:map.keySet()){
    40                 set.add(new WordEntity(key, map.get(key)));
    41             }
    42             /*System.out.print("单词        次数
    ");
    43             for(Iterator<WordEntity> it = set.iterator();it.hasNext();){
    44                 WordEntity w = it.next();
    45                 System.out.println(w.getKey()+"    :"+w.getCount());
    46             }*/
    47     
    48             int count = 1;
    49             for(Iterator<WordEntity> it = set.iterator();it.hasNext();){
    50                 WordEntity w = it.next();
    51                 System.out.println("Top"+count+": "+w.getKey()+"     次数:"+w.getCount());
    52                 if(count == 10){
    53                     break;
    54                 }
    55                 count++;
    56             }
    57         } catch (FileNotFoundException e) {
    58             System.out.println("文件未找到!");
    59         } catch (IOException e){
    60             System.out.println("文件读异常!");
    61         }
    62         long time2 = System.currentTimeMillis();
    63         System.out.println("耗时:");
    64         System.out.println(time2 - time1+"ms");
    65     }
    66 }
     1 package homework;
     2 
     3 public class WordEntity implements Comparable<WordEntity>{
     4     
     5     public WordEntity(String key,Integer count){
     6         this.key = key;
     7         this.count = count;
     8     }
     9 
    10     public String getKey(){
    11         return key;
    12     }
    13     
    14     public Integer getCount(){
    15         return count;
    16     }
    17     
    18     @Override
    19     //cmp升序。-cmp降序排列  TreeSet会调用WorkForMap的compareTo方法来决定自己的排序
    20     public int compareTo(WordEntity o) {
    21         int cmp = count.intValue() - o.count.intValue();
    22         return (cmp == 0 ? key.compareTo(o.key):-cmp); 
    23     }
    24     
    25     @Override
    26     public String toString() {    
    27         return key + "出现次数:" + count;
    28     }
    29     
    30     private String key;
    31     private Integer count;
    32     
    33 }

     

    运行结果:

     
     
     
     
     
     
     
     
     
     
     
     
     

     

    不足与改进:

      单词分割没有考虑全面,比如"_"和"—",还有"单双引号",省略号等,字母的大小写等;改进程序,用正则表达式来匹配单词,存储在TreeMap,要按照TreeMap的value排序,默认是key排序,可以将Map.Entry放在集合里,重写比较器,再用 Collections.sort(list,comparator) 进行排序。
     

    改进代码:

     1 package homework;
     2 
     3 import java.io.BufferedReader;
     4 import java.io.FileReader;
     5 import java.util.ArrayList;
     6 import java.util.Collections;
     7 import java.util.Comparator;
     8 import java.util.List;
     9 import java.util.Map;
    10 import java.util.TreeMap;
    11 import java.util.regex.Matcher;
    12 import java.util.regex.Pattern;
    13 
    14 public class WordCount {
    15     public static void main(String[] args) throws Exception {
    16         
    17         long time1 = System.currentTimeMillis();
    18 
    19         BufferedReader reader = new BufferedReader(new FileReader(
    20                 "D:\wordtest.txt"));
    21         StringBuffer buffer = new StringBuffer();
    22         String line = null;
    23         while ((line = reader.readLine()) != null) {
    24             buffer.append(line);
    25         }
    26         reader.close();
    27         Pattern expression = Pattern.compile("[a-zA-Z]+");// 定义正则表达式匹配单词
    28         String string = buffer.toString();
    29         Matcher matcher = expression.matcher(string);//
    30         Map<String, Integer> map = new TreeMap<String, Integer>();
    31         String word = "";
    32         int times = 0;
    33         while (matcher.find()) {// 是否匹配单词
    34             word = matcher.group();// 得到一个单词-树映射的键
    35             if (map.containsKey(word)) {// 如果包含该键,单词出现过
    36                 times = map.get(word);// 得到单词出现的次数
    37                 map.put(word, times + 1);
    38             } else {
    39                 map.put(word, 1);// 否则单词第一次出现,添加到映射中
    40             }
    41         }
    42         /*
    43          * 核心:如何按照TreeMap 的value排序而不是key排序.将Map.Entry放在集合里,重写比较器,在用
    44          * Collections.sort(list, comparator);进行排序
    45          */
    46 
    47         List<Map.Entry<String, Integer>> list = new ArrayList<Map.Entry<String, Integer>>(
    48                 map.entrySet());
    49         /*
    50          * 重写比较器
    51          * 取出单词个数(value)比较
    52          */
    53         Comparator<Map.Entry<String, Integer>> comparator = new Comparator<Map.Entry<String, Integer>>() {
    54             public int compare(Map.Entry<String, Integer> left,
    55                     Map.Entry<String, Integer> right) {
    56                 return (left.getValue()).compareTo(right.getValue());
    57             }
    58         };
    59         Collections.sort(list, comparator);// 排序
    60         // 打印
    61         int last = list.size() - 1;
    62         for (int i = last; i > last-10; i--) {
    63             String key = list.get(i).getKey();
    64             Integer value = list.get(i).getValue();
    65             System.out.print("Top"+i+"  : ");
    66             System.out.println(key + " " + value);
    67         }
    68         long time2 = System.currentTimeMillis();
    69         System.out.println("耗时:");
    70         System.out.println(time2 - time1+"ms");
    71     }
    72 }

     

    运行结果:

    结果对比:

      程序1 和程序2 结果前9名相似,最后一个虽然不一样,但是出现次数一样,为什么不一样呢?因为程序一里面TreeMap排序是按照key排序,所以虽然次数相同,但是 play 比 was 排在前面。

     

    性能测试:

      1. 整体:

    图1:程序运行前(初始状态)
    程序运行前(初始状态)
     
     
     
     
    图2:程序1 (改进前)测试情况
     
     
     
     
    图3:程序2(改进后)测试情况
     
     
     

      2. CUP & GC

     

     

     

      3. Heap

    程序1

      

      程序2

      4. Threads

    程序1

    程序2

      5. Class

    程序1

     

     

     

    程序2

      
     

    改进与扩展:

      对于处理大数据采用拆分的方法,比较好。使用Java正则表达式,如果文章比较大,会造成栈溢出,因为测试文本在500KB以下,所以没有溢出。但是如果测试很大的文本,就不行。除此之外,还可以进行扩展,可以将正则表达式改变,设计一个对中英文混合,或者中文文件查找算法及程序实现,同时考虑读取存储方式的改进,提高效率和性能。
     
  • 相关阅读:
    爱福窝在线装修设计软件测评
    关于简书首页模式的思考和畅想
    这些O2O比你们更靠谱儿
    iOS动画——Layer Animations
    最大流, 最小割问题及算法实现
    浅谈iOS学习之路
    iOS架构师之路:慎用继承
    iOS架构师之路:控制器(View Controller)瘦身设计
    IOS中的编码规范
    关闭键盘导致tableView:didSelectRowAtIndexPath:失效解决办法
  • 原文地址:https://www.cnblogs.com/Dance-yang/p/3603001.html
Copyright © 2011-2022 走看看