一道筆試題:統計文章中出現的單詞個數


題目要求:

請設計數據結構並寫出算法,統計一篇文章中每個單詞出現的次數,並按單詞在文章中出現的順序輸出單詞及它的個數。

個人思路:

采用了類似鍵樹的思想,用該樹來存儲單詞及某個單詞出現的次數;樹從根節點到葉子節點組成一個單詞,每個節點只存儲該單詞里的某個字符;

用孩子兄弟法表示樹,用左孩子記錄某個單詞出現的次數(參見樹結構圖),可讓每個單詞必有左孩子(創建新節點同時創建左孩子)。

這樣就能得到單詞及其個數,題目中要求按出現順序輸出可以用一個list或vector存放單詞記錄,該記錄里存放單詞及指向代表該單詞訪問記錄數的樹節點指針,這樣文章讀完后,將list或vector里的記錄輸出即可。

 

其它思路:

(1)可以用stl里的map實現

(2)可以將單詞hash,存放在一個數組里,若hash沖突,采用鏈地址法,在數組元素后添加鏈表存放單詞及次數,同時將首次出現的記錄指針存放到Vector或list中

 

實現:

定義樹結構及單詞記錄如下:

//孩子兄弟法表示樹
typedef struct KeyNode
{
    char data;
    unsigned int count;
    struct KeyNode *son,*next;
}*KeyTree;

//單詞記錄
//存放單詞及指向單詞出現數的節點的指針
struct TWord
{
string word;
struct KeyNode* pNode;
};

 樹結構示意圖:

 

上圖展示的是查詢過單詞"ah","she"后形成的樹;

 以"ah"單詞訪問為例,描述如何構造樹:

(1)初始化一個樹,生成一個根節點和一存放空字符的左孩子

(2)單詞"ah",先從樹中找字符'o',沒找到,則在樹根插入節點,賦值為'a',同時創建存放空字符的左孩子,次數設為0(這個次數,表示單詞"a"出現的次數)

(3)之后按同樣方法將字符'h'按(2)中方法生成新節點插入到(2)中生成節點'a'下

(4)單詞讀完,將'h'的左子樹出現次數+1,表示單詞"ah"出現次數為1;同時將該左子樹指針與單詞名放入vector

(5)同樣方法生成"she"單詞及其次數

 若出現同樣的單詞,只需將單詞對應的尾字符的左孩子節點次數+1即可。

 查找及插入單詞用到的函數:

//從給定鍵樹中查看是否存在字符串pStr,
//若存在返回true,若是第一次查詢該字符串,則記字符串為首次查詢且用p返回
//指向該字符串結束葉子節點的指針;
//若不存在返回false
bool FindString(const KeyTree pTree,char* pStart,const char* pEnd,bool& isFirstFind,KeyTree& p)
{
    assert(pTree!=NULL && pTree->son!=NULL);
    assert(pStart!=NULL);
    assert(pEnd!=NULL);
    char* pCur = pStart;
    KeyTree pCurTree = pTree->son;
    while(pCurTree)
    {
        KeyTree pNext = pCurTree->next;
        //從兄弟中找相應字符直到找到若兄弟為空
        while(pNext && pNext->data!=*pCur)
        {
            pNext = pNext->next;
        }
        //沒找到
        if(pNext==NULL) return false;
        //找到進入下一層判斷
        pCurTree = pNext->son;
        pCur++;

        //字符串匹配結束,成功找到
        if(pCur>pEnd) break;
    }

    KeyTree pSon = pCurTree;
    //第一次訪問,孩子節點不存在,創建
    if(pSon == NULL)
    {
        pSon = CreateKeyNode(END_WORD);
        pSon->count = 1;
        isFirstFind = true;
        p = pSon;
    }
    else
    {
        //出現次數+1
        pSon->count++;
        if(pSon->count==1)
        {
            isFirstFind = true;
            p = pSon;
        }
    }
    return true;
}

 

//將字符串插入到鍵樹中
//從第一個不匹配的字符開始創建新樹節點存儲字符串里的字符
//p返回指向該字符串結束葉子節點的指針
bool Insert(const KeyTree pTree,char* pStr,const char* pEnd,KeyTree& p)
{
    assert(pTree!=NULL && pTree->son!=NULL);
    assert(pStr!=NULL);
    assert(pEnd!=NULL);

    char* pCur = pStr;
    KeyTree pCurTree = pTree->son;
    while(pCur<=pEnd)
    {
        KeyTree pNext = pCurTree->next;
        
        //從兄弟中找對應字符,直至找到或找完所有兄弟
        while(pNext && pNext->data!=*pCur) 
        {
            pCurTree = pNext;
            pNext = pNext->next;
        }
        //未找到,則創建
        if(pNext==NULL)
        {
            pNext = CreateKeyNode(*pCur);
            pNext->son = CreateKeyNode(END_WORD);
            pCurTree->next = pNext;
        }

        //當前字符匹配完成,匹配下一個字符
        pCurTree = pNext->son;
        pCur++;
    }

    //出現次數+1
    pCurTree->count++;
    p = pCurTree;
    return true;
}

對字符串的輸出:

 

附上源碼文件:類鍵樹統計字符串個數.zip


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM