1. 程式人生 > >第一次個人項目【詞頻統計】——關鍵程序思路詳述

第一次個人項目【詞頻統計】——關鍵程序思路詳述

個人項目 在一起 文件讀取 conn 好的 函數 orm get insert

  考慮使用平衡二叉樹實現單詞和詞組數目的統計。

  二叉樹節點定義:

1 struct tnode {
2     char *word;
3     int count;
4     int height; //record node‘s height
5     struct tnode *left;
6     struct tnode *right;
7 };

  節點中的成員char *word既可以存儲單詞,也可以存儲詞組。比較好的體現了該數據結構的復用屬性。

  

  【判斷字符數邏輯】

  逐字符讀取文件,如果該字符在32-126之間,則字符總數+1。

  【判斷行數邏輯】

  逐字符讀取,如果該字符為‘\n’,則總行數+1,單個文件讀取結束後總函數再+1(因為文件結束符為EOF,不是‘\n’)。

  【判斷單詞數邏輯】

  遍歷單詞樹,采用遞歸的方式計算總單詞數。

1 long count_tree(struct tnode *root) {
2     if (root == NULL) return 0;
3     else return count_tree((*root).left) + count_tree((*root).right) + root->count;
4 }

  【判斷單詞邏輯】

  設置單詞開始標誌符bool isWordStart,然後根據標誌符和當前讀入的字符綜合判斷後續操作。不是單詞開始且讀到了字符,則開始記錄單詞。單詞開始且讀到的是字符或者數字,則繼續記錄,如果單詞開始且讀到了非字母數字字符則停止記錄並並標誌符置為false.

// 讀到單詞起始字母
if (!isWordStart && isCharacter(charTemp)) {
    isWordStart = true;
    lengthofStr = 1;
    str[0] = charTemp;
}
// 讀單詞(字母或者數字)
else if (isWordStart && isNumorCharacter(charTemp)) {
    str[lengthofStr++] = charTemp;
}
// 單詞讀完後讀到第一個分隔符
else if (isWordStart && !isNumorCharacter(charTemp)) {
    isWordStart 
= false; str[lengthofStr] = \0; }

  【單詞樹的動態維護】

  由於最後輸出要輸出同類型詞組排序最小的單詞,因此在插入單詞樹時需要動態維護節點存儲的單詞。

  

  【詞組樹的判斷邏輯】

  設置一個臨時變量存儲上次讀到的單詞。

  如果是當前讀到的單詞總數為1,則不插入詞組樹,否則將該次讀到的單詞和上次讀到的單詞用空格分隔符拼接在一起,插入詞組樹。

// 若單詞符合要求則插入樹
if (lengthofStr >= 4 && isCharacter(str[1]) && isCharacter(str[2]) && isCharacter(str[3])) {
    //將單詞插入單詞樹
    numofAllWord++;
    root = insert_balance(root, str);

    //總共只掃描到一個單詞,不插入詞組樹
    if (numofAllWord == 1) {
        str_copy(str_before, str);
    }
    //總共掃描到至少兩個單詞,插入詞組樹
    else {
        phrase = str_connectwithSpace(str_before, str);
        rootofPhrase = insert_balance_phrase(rootofPhrase, phrase);
        str_copy(str_before, str);
    }

}

  核心計數函數:

void getInformationofOneFile(char *filename, long &numofChararcter, long &numofLine, tnode *&root, tnode *&rootofPhrase) {
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        return;
    }

    char str[STRING_MAX_LEN], str_before[STRING_MAX_LEN], *phrase = NULL;
    long numofAllCharacter = 0;    //單篇文章所有ascii字符數目
    long numofAllWord = 0;           //單篇文章所有詞組數目      
    bool isWordStart = false;
    bool isEmptyFile = false;
    int lengthofStr = 0;
    char charTemp;
    do {
        charTemp = fgetc(fp);

        if (charTemp == EOF &&numofAllCharacter == 0) {
            isEmptyFile = true;
            break;
        }
        numofAllCharacter++;

        if (charTemp >= 32 && charTemp <= 126) numofChararcter++;
        if (charTemp == \n) numofLine++;

        // 讀到單詞起始字母
        if (!isWordStart && isCharacter(charTemp)) {
            isWordStart = true;
            lengthofStr = 1;
            str[0] = charTemp;
        }
        // 讀單詞(字母或者數字)
        else if (isWordStart && isNumorCharacter(charTemp)) {
            str[lengthofStr++] = charTemp;
        }
        // 單詞讀完後讀到第一個分隔符
        else if (isWordStart && !isNumorCharacter(charTemp)) {
            isWordStart = false;
            str[lengthofStr] = \0;
            // 若單詞符合要求則插入樹
            if (lengthofStr >= 4 && isCharacter(str[1]) && isCharacter(str[2]) && isCharacter(str[3])) {
                //將單詞插入單詞樹
                numofAllWord++;
                root = insert_balance(root, str);

                //總共只掃描到一個單詞,不插入詞組樹
                if (numofAllWord == 1) {
                    str_copy(str_before, str);
                }
                //總共掃描到至少兩個單詞,插入詞組樹
                else {
                    phrase = str_connectwithSpace(str_before, str);
                    rootofPhrase = insert_balance_phrase(rootofPhrase, phrase);
                    str_copy(str_before, str);
                }

                //[DEBUG][DEBUG][DEBUG][DEBUG][DEBUG][DEBUG]
                //cout << numofAllWord << endl;
                //travel_tree(rootofPhrase);

            }
        }
    } while (charTemp != EOF);

    if (!isEmptyFile) numofLine++;
    //numofLine++;

    fclose(fp);
}

  

第一次個人項目【詞頻統計】——關鍵程序思路詳述