1. 程式人生 > >Java詞頻統計演算法(使用單詞樹)

Java詞頻統計演算法(使用單詞樹)

許多英語培訓機構(如新東方)都會出幾本“高頻詞彙”的書,主要內容是統計近幾年來各類外語考試中屢次出現的高頻詞彙,幫助考生減少需要背的生詞的數量。但這些高頻是如何被統計出來的呢?顯然不會用手工去計算。
假如我們已經將一篇文章存在一字串(String)物件中,為了統計詞彙出現頻率,最簡單直接的做法是另外建一個Map:key是單詞,value是 次數。將文章從頭讀到尾,讀到一個單詞就到Map裡查一下,如果查到了則次數加一,沒查到則往Map裡一扔。這樣做雖然程式碼寫起來簡單,但效能卻非常差。 首先查詢Map的代價是O(logn),假設文章的字母數為m,則整個統計程式的時間複雜度為O(mlogn)不說,如果要拿高頻詞可能還需要對統計結果 進行排序。即便對結構上進行優化效能仍然不高。如果能夠將時間複雜度從O(mlogn)減少到O(m)的話不是更好?

為了改進演算法我們首先引進單詞樹。與單詞字首樹不同,單詞樹的結構相當簡單,結構如圖所示:

  從圖中我們可以看出,樹中每個結點儲存屬性值cnt與指向其26個子結點的指標(每一條路徑代表一個英文字母),其中cnt為到達該結點經過路 徑所對應的英文單詞在文章中出現的次數。也就是說,我們開始讀文章時讓一個指標指向單詞數的根結點,之後每度一個字母就讓該指標指向當前結點對應路徑上的 子結點(若子結點為空則新建一個),一個單詞讀完後讓當前結點的cnt值加一,並讓指標重新指向根結點。而當一篇文章讀完之後我們的單詞樹也就已經建立完 畢了。之後只要去遍歷它並把取到的單詞根據次數進行排序就行了(時間複雜度為O(nlogn))。

  程式程式碼如下,首先是存放單詞及出現次數的JavaBean

  1. public class WordCount {
  2.     private String word;
  3.     private int count;
  4.     public int getCount() {
  5.         return count;
  6.     }
  7.     public void setCount(int count) {
  8.         this.count = count;
  9.     }
  10.     public String getWord() {
  11.         return word;
  12.     }
  13.     public void setWord(String word) {
  14.         this.word = word;
  15.     }
  16. }

  其次是實現詞頻表生成演算法的類:

  1. public class WordCountService {
  2.     /**
  3.      * 根據文章生成單詞樹
  4.      * @param text
  5.      * @return
  6.      */
  7.     private static CharTreeNode geneCharTree(String text){
  8.         CharTreeNode root = new CharTreeNode();
  9.         CharTreeNode p = root;
  10.         char c = ' ';
  11.         for(int i = 0; i < text.length(); ++i){
  12.             c = text.charAt(i);
  13.             if(c >= 'A' && c <= 'Z')
  14.                 c = (char)(c + 'a' - 'A');
  15.             if(c >= 'a' && c <= 'z'){
  16.                 if(p.children[c-'a'] == null)
  17.                     p.children[c-'a'] = new CharTreeNode();
  18.                 p = p.children[c-'a'];
  19.             }
  20.             else{
  21.                 p.cnt ++;
  22.                 p = root;
  23.             }
  24.         }
  25.         if(c >= 'a' && c <= 'z')
  26.             p.cnt ++;
  27.         return root;
  28.     }
  29.     /**
  30.      * 使用深度優先搜尋遍歷單詞樹並將對應單詞放入結果集中
  31.      * @param result
  32.      * @param p
  33.      * @param buffer
  34.      * @param length
  35.      */
  36.     private static void getWordCountFromCharTree(List result,CharTreeNode p, char[] buffer, int length){
  37.         for(int i = 0; i < 26; ++i){
  38.             if(p.children[i] != null){
  39.                 buffer[length] = (char)(i + 'a');
  40.                 if(p.children[i].cnt > 0){
  41.                     WordCount wc = new WordCount();
  42.                     wc.setCount(p.children[i].cnt);
  43.                     wc.setWord(String.valueOf(buffer, 0, length+1));
  44.                     result.add(wc);
  45.                 }
  46.                 getWordCountFromCharTree(result,p.children[i],buffer,length+1);
  47.             }
  48.         }
  49.     }
  50.     private static void getWordCountFromCharTree(List result,CharTreeNode p){
  51.         getWordCountFromCharTree(result,p,new char[100],0);
  52.     }
  53.     /**
  54.      * 得到詞頻表的主演算法,供外部呼叫
  55.      * @param article
  56.      * @return
  57.      */
  58.     public static List getWordCount(String article){
  59.         CharTreeNode root = geneCharTree(article);
  60.         List result = new ArrayList();//此處也可用LinkedList連結串列,以避免陣列滿了擴容導致的效能損失
  61.         getWordCountFromCharTree(result,root);
  62.         Collections.sort(result, new Comparator(){
  63.             public int compare(Object o1, Object o2) {
  64.                 WordCount wc1 = (WordCount)o1;
  65.                 WordCount wc2 = (WordCount)o2;
  66.                 return wc2.getCount() - wc1.getCount();
  67.             }
  68.         });
  69.         return result;
  70.     }
  71. }
  72. /**
  73.  * 單詞樹結點的定義
  74.  * @author FlameLiu
  75.  *
  76.  */
  77. class CharTreeNode{
  78.     int cnt = 0;
  79.     CharTreeNode[] children = new CharTreeNode[26];
  80. }

相關推薦

Java詞頻統計演算法使用單詞

許多英語培訓機構(如新東方)都會出幾本“高頻詞彙”的書,主要內容是統計近幾年來各類外語考試中屢次出現的高頻詞彙,幫助考生減少需要背的生詞的數量。但這些高頻是如何被統計出來的呢?顯然不會用手工去計算。假如我們已經將一篇文章存在一字串(String)物件中,為了統計詞彙出現頻率

[ACM] hdu 1251 統計難題 字典

第一次 stdio.h scrip null 明顯 output 代碼 ane 處理 統計難題 Problem Description Ignatius近期遇到一個難題,老師交給他非常多單詞(僅僅有小寫字母組成,不會有反復的單詞出現),如今老師要他統計出以某

HDU1251 統計難題字典

lag != tac NPU math def tput struct bee HDU1251 統計難題 Ignatius最近遇到一個難題,老師交給他很多單詞(只有小寫字母組成,不會有重復的單詞出現),現在老師要他統計出以某個字符串為前綴的單詞數量(單詞本身也是自己的前綴)

HDU 1251 - 統計難題 字典

Ignatius最近遇到一個難題,老師交給他很多單詞(只有小寫字母組成,不會有重複的單詞出現),現在老師要他統計出以某個字串為字首的單詞數量(單詞本身也是自己的字首). Input 輸入資料的第一部分是一張單詞表,每行一個單詞,單詞的長度不超過10,它們代表的是老師交給Ignatius統計的

HDU 1251 統計難題字典

#include<stdio.h> #include<string.h> struct Node { Node *next[26];//每個節點的分支由單詞性質決定,這裡是小寫的26個字母 int cnt;//每個節點可以儲存一些資訊,這道題是儲存該字首的數量 Node()

演算法--統計文字中出現次數最多的單詞字典

統計一個文字中,出現次數最多的單詞:單詞全部小寫,單詞與單詞之間以空格間隔 1.利用字典  key為單詞  value為單詞出現的次數 def mostString(): dict = {} fr = open('preprocessing.txt')

使用單詞進行詞頻統計演算法

許多英語培訓機構(如新東方)都會出幾本“高頻詞彙”的書,主要內容是統計近幾年來各類外語考試中屢次出現的高頻詞彙,幫助考生減少需要背的生詞的數量。但這些高頻是如何被統計出來的呢?顯然不會用手工去計算。   假如我們已經將一篇文章存在一字串(String)物件中,為了統計詞

【LeetCode-面試算法經典-Java實現】【139-Word Break單詞拆分

put art als min 全部 detail set 長度 trac 【139-Word Break(單詞拆分)】 【LeetCode-面試算法經典-Java實現】【全部題目文件夾索引】 原題   Given a string s a

統計難題HDU-1251字典

wkt mtu shp isl com shuf rrd xe8 xdg yhly5c梅覆來粕倜叛http://docstore.docin.com/sina_6341912133p1s7b1澇淪家濤缺細http://www.docin.com/gxk352s1mtus俟酚

[Bzoj3172][Tjoi2013]單詞fail

print bmi output bzoj tin ref des HP sin 3172: [Tjoi2013]單詞 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 4777 Solved: 2345[Su

【HDU - 1251 】統計難題字典,求擁有公共字首的字串數量

題幹: Ignatius最近遇到一個難題,老師交給他很多單詞(只有小寫字母組成,不會有重複的單詞出現),現在老師要他統計出以某個字串為字首的單詞數量(單詞本身也是自己的字首).  Input 輸入資料的第一部分是一張單詞表,每行一個單詞,單詞的長度不超過10,它們代表的是老

Java-經典排序演算法

前言: 排序演算法有很多種,如選擇排序、插入排序、氣泡排序、桶排序、快速排序等等。這裡介紹的是簡化版桶排序、氣泡排序和插入排序。 推薦一本演算法入門書——《啊哈!演算法》 1. 桶排序[簡化版]: 原理:新建一個book陣列用來標記原陣列每一個數字出現的個數。

面試前的準備java專業 ~學習演算法排序以及查詢

java專業的馬上大三,東西學的差不多,但是資料結構這塊特別薄弱,所以面試前對自己資料結構進行鞏固複習(PS:其實是預習啦~) 針對自己薄弱的幾塊進行記錄:(排序和查詢) 每天都在叫囂自己會什麼技術,什麼框架,可否意識到你每天都在被這些新名詞、新技術所迷惑,.NET、

二叉的遍歷演算法js實現

之前我的部落格中講到了如何通過js去實現一顆二叉樹,有興趣的可以去我的部落格中看下。今天我們來一起實現下二叉樹的遍歷演算法。歡迎大家幫忙指出不當之處,或者進行深入的挖掘。大家一起進步。二叉樹吶,有三種遍歷演算法,1:中序遍歷,2:先序遍歷,3:後序遍歷。在我們看具體實現之前,我們想下為什麼要這樣做?二叉樹廣泛

Java中常用的排序演算法動態演示

1.前言 這篇文章講解的是Java中或者面試中常用的**排序演算法**。 文章中例項  [linhaojian的Github](https://github.com/linhaojian 2.複雜度 相關概率

決策、隨機森林整合演算法Titanic例項

#coding:utf-8 import pandas #ipython notebook titanic = pandas.read_csv("titanic_train.csv") titanic.head(5) #print (titanic.describe()) t

Trie字典:應用於統計和排序

轉載這篇關於字典樹的原因是看到騰訊面試相關的題:就是在海量資料中找出某一個數,比如2億QQ號中查找出某一個特定的QQ號。。 有人提到字典樹,我就順便了解下字典樹。 [轉自:http://blog.csdn.net/oncealong/article/details

bzoj1588: [HNOI2002]營業額統計平衡

原題連結 題目描述:營業額統計 Tiger最近被公司升任為營業部經理,他上任後接受公司交給的第一項任務便是統計並分析公司成立以來的營業情況。 Tiger拿出了公司的賬本,賬本上記錄了公司成立以來每天的營業額。分析營業情況是一項相當複雜的工作。由於節假日,大減價或者是其他情況的時候,營業額會出現一定的波動,當

字典Trie附例題統計難題 HDU

一、基礎理論:        字典樹,又稱單詞查詢樹,Trie樹,是一種樹形結構,是一種雜湊樹的變種。典型應用是用於統計,排序和儲存大量的字串(但不僅限於字串),所以經常被搜尋引擎系統用於文字詞頻統計。 二、基本性質: 根節點不包含字元,除根節點之外每個子節點都包含一個

快速查詢區間最值——RMQ演算法線段實現程式碼

要求找出區間內的最大最小值的差。 #include<stdio.h> #include<string.h> #include<math.h> #define lso